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

db_load.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_load.c,v 12.8 2005/06/16 20:21:23 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 <limits.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #endif
00026 
00027 #include "db_int.h"
00028 #include "dbinc/db_page.h"
00029 #include "dbinc/db_am.h"
00030 
00031 typedef struct {                        /* XXX: Globals. */
00032         const char *progname;           /* Program name. */
00033         char    *hdrbuf;                /* Input file header. */
00034         u_long  lineno;                 /* Input file line number. */
00035         u_long  origline;               /* Original file line number. */
00036         int     endodata;               /* Reached the end of a database. */
00037         int     endofile;               /* Reached the end of the input. */
00038         int     version;                /* Input version. */
00039         char    *home;                  /* Env home. */
00040         char    *passwd;                /* Env passwd. */
00041         int     private;                /* Private env. */
00042         u_int32_t cache;                /* Env cache size. */
00043 } LDG;
00044 
00045 void    db_load_badend __P((DB_ENV *));
00046 void    db_load_badnum __P((DB_ENV *));
00047 int     db_load_configure __P((DB_ENV *, DB *, char **, char **, int *));
00048 int     db_load_convprintable __P((DB_ENV *, char *, char **));
00049 int     db_load_db_init __P((DB_ENV *, char *, u_int32_t, int *));
00050 int     db_load_dbt_rdump __P((DB_ENV *, DBT *));
00051 int     db_load_dbt_rprint __P((DB_ENV *, DBT *));
00052 int     db_load_dbt_rrecno __P((DB_ENV *, DBT *, int));
00053 int     db_load_dbt_to_recno __P((DB_ENV *, DBT *, db_recno_t *));
00054 int     db_load_digitize __P((DB_ENV *, int, int *));
00055 int     db_load_env_create __P((DB_ENV **, LDG *));
00056 int     db_load_load __P((DB_ENV *, char *, DBTYPE, char **, u_int, LDG *, int *));
00057 int     db_load_main __P((int, char *[]));
00058 int     db_load_rheader __P((DB_ENV *, DB *, DBTYPE *, char **, int *, int *));
00059 int     db_load_usage __P((void));
00060 int     db_load_version_check __P((void));
00061 
00062 const char *progname;
00063 
00064 #define G(f)    ((LDG *)dbenv->app_private)->f
00065 
00066                                         /* Flags to the load function. */
00067 #define LDF_NOHEADER    0x01            /* No dump header. */
00068 #define LDF_NOOVERWRITE 0x02            /* Don't overwrite existing rows. */
00069 #define LDF_PASSWORD    0x04            /* Encrypt created databases. */
00070 
00071 int
00072 db_load(args)
00073         char *args;
00074 {
00075         int argc;
00076         char **argv;
00077 
00078         __db_util_arg("db_load", args, &argc, &argv);
00079         return (db_load_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS);
00080 }
00081 
00082 #include <stdio.h>
00083 #define ERROR_RETURN    ERROR
00084 
00085 int
00086 db_load_main(argc, argv)
00087         int argc;
00088         char *argv[];
00089 {
00090         enum { NOTSET, FILEID_RESET, LSN_RESET, STANDARD_LOAD } mode;
00091         extern char *optarg;
00092         extern int optind, __db_getopt_reset;
00093         DBTYPE dbtype;
00094         DB_ENV  *dbenv;
00095         LDG ldg;
00096         u_int ldf;
00097         int ch, existed, exitval, ret;
00098         char **clist, **clp;
00099 
00100         if ((progname = strrchr(argv[0], '/')) == NULL)
00101                 progname = argv[0];
00102         else
00103                 ++progname;
00104 
00105         if ((ret = db_load_version_check()) != 0)
00106                 return (ret);
00107 
00108         ldg.progname = progname;
00109         ldg.lineno = 0;
00110         ldg.endodata = ldg.endofile = 0;
00111         ldg.version = 1;
00112         ldg.cache = MEGABYTE;
00113         ldg.hdrbuf = NULL;
00114         ldg.home = NULL;
00115         ldg.passwd = NULL;
00116 
00117         mode = NOTSET;
00118         ldf = 0;
00119         exitval = existed = 0;
00120         dbtype = DB_UNKNOWN;
00121 
00122         /* Allocate enough room for configuration arguments. */
00123         if ((clp = clist =
00124             (char **)calloc((size_t)argc + 1, sizeof(char *))) == NULL) {
00125                 fprintf(stderr, "%s: %s\n", ldg.progname, strerror(ENOMEM));
00126                 return (EXIT_FAILURE);
00127         }
00128 
00129         /*
00130          * There are two modes for db_load: -r and everything else.  The -r
00131          * option zeroes out the database LSN's or resets the file ID, it
00132          * doesn't really "load" a new database.  The functionality is in
00133          * db_load because we don't have a better place to put it, and we
00134          * don't want to create a new utility for just that functionality.
00135          */
00136         __db_getopt_reset = 1;
00137         while ((ch = getopt(argc, argv, "c:f:h:nP:r:Tt:V")) != EOF)
00138                 switch (ch) {
00139                 case 'c':
00140                         if (mode != NOTSET && mode != STANDARD_LOAD)
00141                                 return (db_load_usage());
00142                         mode = STANDARD_LOAD;
00143 
00144                         *clp++ = optarg;
00145                         break;
00146                 case 'f':
00147                         if (mode != NOTSET && mode != STANDARD_LOAD)
00148                                 return (db_load_usage());
00149                         mode = STANDARD_LOAD;
00150 
00151                         if (freopen(optarg, "r", stdin) == NULL) {
00152                                 fprintf(stderr, "%s: %s: reopen: %s\n",
00153                                     ldg.progname, optarg, strerror(errno));
00154                                 return (EXIT_FAILURE);
00155                         }
00156                         break;
00157                 case 'h':
00158                         ldg.home = optarg;
00159                         break;
00160                 case 'n':
00161                         if (mode != NOTSET && mode != STANDARD_LOAD)
00162                                 return (db_load_usage());
00163                         mode = STANDARD_LOAD;
00164 
00165                         ldf |= LDF_NOOVERWRITE;
00166                         break;
00167                 case 'P':
00168                         ldg.passwd = strdup(optarg);
00169                         memset(optarg, 0, strlen(optarg));
00170                         if (ldg.passwd == NULL) {
00171                                 fprintf(stderr, "%s: strdup: %s\n",
00172                                     ldg.progname, strerror(errno));
00173                                 return (EXIT_FAILURE);
00174                         }
00175                         ldf |= LDF_PASSWORD;
00176                         break;
00177                 case 'r':
00178                         if (mode == STANDARD_LOAD)
00179                                 return (db_load_usage());
00180                         if (strcmp(optarg, "lsn") == 0)
00181                                 mode = LSN_RESET;
00182                         else if (strcmp(optarg, "fileid") == 0)
00183                                 mode = FILEID_RESET;
00184                         else
00185                                 return (db_load_usage());
00186                         break;
00187                 case 'T':
00188                         if (mode != NOTSET && mode != STANDARD_LOAD)
00189                                 return (db_load_usage());
00190                         mode = STANDARD_LOAD;
00191 
00192                         ldf |= LDF_NOHEADER;
00193                         break;
00194                 case 't':
00195                         if (mode != NOTSET && mode != STANDARD_LOAD)
00196                                 return (db_load_usage());
00197                         mode = STANDARD_LOAD;
00198 
00199                         if (strcmp(optarg, "btree") == 0) {
00200                                 dbtype = DB_BTREE;
00201                                 break;
00202                         }
00203                         if (strcmp(optarg, "hash") == 0) {
00204                                 dbtype = DB_HASH;
00205                                 break;
00206                         }
00207                         if (strcmp(optarg, "recno") == 0) {
00208                                 dbtype = DB_RECNO;
00209                                 break;
00210                         }
00211                         if (strcmp(optarg, "queue") == 0) {
00212                                 dbtype = DB_QUEUE;
00213                                 break;
00214                         }
00215                         return (db_load_usage());
00216                 case 'V':
00217                         printf("%s\n", db_version(NULL, NULL, NULL));
00218                         return (EXIT_SUCCESS);
00219                 case '?':
00220                 default:
00221                         return (db_load_usage());
00222                 }
00223         argc -= optind;
00224         argv += optind;
00225 
00226         if (argc != 1)
00227                 return (db_load_usage());
00228 
00229         /* Handle possible interruptions. */
00230         __db_util_siginit();
00231 
00232         /*
00233          * Create an environment object initialized for error reporting, and
00234          * then open it.
00235          */
00236         if (db_load_env_create(&dbenv, &ldg) != 0)
00237                 goto shutdown;
00238 
00239         /* If we're resetting the LSNs, that's an entirely separate path. */
00240         switch (mode) {
00241         case FILEID_RESET:
00242                 exitval = dbenv->fileid_reset(
00243                     dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0);
00244                 break;
00245         case LSN_RESET:
00246                 exitval = dbenv->lsn_reset(
00247                     dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0);
00248                 break;
00249         case NOTSET:
00250         case STANDARD_LOAD:
00251                 while (!ldg.endofile)
00252                         if (db_load_load(dbenv, argv[0], dbtype, clist, ldf,
00253                             &ldg, &existed) != 0)
00254                                 goto shutdown;
00255                 break;
00256         }
00257 
00258         if (0) {
00259 shutdown:       exitval = 1;
00260         }
00261         if ((ret = dbenv->close(dbenv, 0)) != 0) {
00262                 exitval = 1;
00263                 fprintf(stderr,
00264                     "%s: dbenv->close: %s\n", ldg.progname, db_strerror(ret));
00265         }
00266 
00267         /* Resend any caught signal. */
00268         __db_util_sigresend();
00269         free(clist);
00270         if (ldg.passwd != NULL)
00271                 free(ldg.passwd);
00272 
00273         /*
00274          * Return 0 on success, 1 if keys existed already, and 2 on failure.
00275          *
00276          * Technically, this is wrong, because exit of anything other than
00277          * 0 is implementation-defined by the ANSI C standard.  I don't see
00278          * any good solutions that don't involve API changes.
00279          */
00280         return (exitval == 0 ? (existed == 0 ? 0 : 1) : 2);
00281 }
00282 
00283 /*
00284  * load --
00285  *      Load a database.
00286  */
00287 int
00288 db_load_load(dbenv, name, argtype, clist, flags, ldg, existedp)
00289         DB_ENV *dbenv;
00290         char *name, **clist;
00291         DBTYPE argtype;
00292         u_int flags;
00293         LDG *ldg;
00294         int *existedp;
00295 {
00296         DB *dbp;
00297         DBT key, rkey, data, *readp, *writep;
00298         DBTYPE dbtype;
00299         DB_TXN *ctxn, *txn;
00300         db_recno_t recno, datarecno;
00301         u_int32_t put_flags;
00302         int ascii_recno, checkprint, hexkeys, keyflag, keys, resize, ret, rval;
00303         char *subdb;
00304 
00305         put_flags = LF_ISSET(LDF_NOOVERWRITE) ? DB_NOOVERWRITE : 0;
00306         G(endodata) = 0;
00307 
00308         subdb = NULL;
00309         ctxn = txn = NULL;
00310         memset(&key, 0, sizeof(DBT));
00311         memset(&data, 0, sizeof(DBT));
00312         memset(&rkey, 0, sizeof(DBT));
00313 
00314 retry_db:
00315         dbtype = DB_UNKNOWN;
00316         keys = -1;
00317         hexkeys = -1;
00318         keyflag = -1;
00319 
00320         /* Create the DB object. */
00321         if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
00322                 dbenv->err(dbenv, ret, "db_create");
00323                 goto err;
00324         }
00325 
00326         /* Read the header -- if there's no header, we expect flat text. */
00327         if (LF_ISSET(LDF_NOHEADER)) {
00328                 checkprint = 1;
00329                 dbtype = argtype;
00330         } else {
00331                 if (db_load_rheader(dbenv,
00332                     dbp, &dbtype, &subdb, &checkprint, &keys) != 0)
00333                         goto err;
00334                 if (G(endofile))
00335                         goto done;
00336         }
00337 
00338         /*
00339          * Apply command-line configuration changes.  (We apply command-line
00340          * configuration changes to all databases that are loaded, e.g., all
00341          * subdatabases.)
00342          */
00343         if (db_load_configure(dbenv, dbp, clist, &subdb, &keyflag))
00344                 goto err;
00345 
00346         if (keys != 1) {
00347                 if (keyflag == 1) {
00348                         dbp->err(dbp, EINVAL, "No keys specified in file");
00349                         goto err;
00350                 }
00351         }
00352         else if (keyflag == 0) {
00353                 dbp->err(dbp, EINVAL, "Keys specified in file");
00354                 goto err;
00355         }
00356         else
00357                 keyflag = 1;
00358 
00359         if (dbtype == DB_BTREE || dbtype == DB_HASH) {
00360                 if (keyflag == 0)
00361                         dbp->err(dbp,
00362                             EINVAL, "Btree and Hash must specify keys");
00363                 else
00364                         keyflag = 1;
00365         }
00366 
00367         if (argtype != DB_UNKNOWN) {
00368 
00369                 if (dbtype == DB_RECNO || dbtype == DB_QUEUE)
00370                         if (keyflag != 1 && argtype != DB_RECNO &&
00371                             argtype != DB_QUEUE) {
00372                                 dbenv->errx(dbenv,
00373                            "improper database type conversion specified");
00374                                 goto err;
00375                         }
00376                 dbtype = argtype;
00377         }
00378 
00379         if (dbtype == DB_UNKNOWN) {
00380                 dbenv->errx(dbenv, "no database type specified");
00381                 goto err;
00382         }
00383 
00384         if (keyflag == -1)
00385                 keyflag = 0;
00386 
00387         /*
00388          * Recno keys have only been printed in hexadecimal starting
00389          * with db_dump format version 3 (DB 3.2).
00390          *
00391          * !!!
00392          * Note that version is set in db_load_rheader(), which must be called before
00393          * this assignment.
00394          */
00395         hexkeys = (G(version) >= 3 && keyflag == 1 && checkprint == 0);
00396 
00397         if (keyflag == 1 && (dbtype == DB_RECNO || dbtype == DB_QUEUE))
00398                 ascii_recno = 1;
00399         else
00400                 ascii_recno = 0;
00401 
00402         /* If configured with a password, encrypt databases we create. */
00403         if (LF_ISSET(LDF_PASSWORD) &&
00404             (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) {
00405                 dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT");
00406                 goto err;
00407         }
00408 
00409 #if 0
00410         Set application-specific btree comparison or hash functions here.
00411         For example:
00412 
00413         if ((ret = dbp->set_bt_compare(dbp, local_comparison_func)) != 0) {
00414                 dbp->err(dbp, ret, "DB->set_bt_compare");
00415                 goto err;
00416         }
00417         if ((ret = dbp->set_h_hash(dbp, local_hash_func)) != 0) {
00418                 dbp->err(dbp, ret, "DB->set_h_hash");
00419                 goto err;
00420         }
00421 #endif
00422 
00423         /* Open the DB file. */
00424         if ((ret = dbp->open(dbp, NULL, name, subdb, dbtype,
00425             DB_CREATE | (TXN_ON(dbenv) ? DB_AUTO_COMMIT : 0),
00426             __db_omode("rw-rw-rw-"))) != 0) {
00427                 dbp->err(dbp, ret, "DB->open: %s", name);
00428                 goto err;
00429         }
00430         if (ldg->private != 0) {
00431                 if ((ret = __db_util_cache(dbp, &ldg->cache, &resize)) != 0)
00432                         goto err;
00433                 if (resize) {
00434                         if ((ret = dbp->close(dbp, 0)) != 0)
00435                                 goto err;
00436                         dbp = NULL;
00437                         if ((ret = dbenv->close(dbenv, 0)) != 0)
00438                                 goto err;
00439                         if ((ret = db_load_env_create(&dbenv, ldg)) != 0)
00440                                 goto err;
00441                         goto retry_db;
00442                 }
00443         }
00444 
00445         /* Initialize the key/data pair. */
00446         readp = writep = &key;
00447         if (dbtype == DB_RECNO || dbtype == DB_QUEUE) {
00448                 key.size = sizeof(recno);
00449                 if (keyflag) {
00450                         key.data = &datarecno;
00451                         if (checkprint) {
00452                                 readp = &rkey;
00453                                 goto key_data;
00454                         }
00455                 } else
00456                         key.data = &recno;
00457         } else
00458 key_data:       if ((readp->data = malloc(readp->ulen = 1024)) == NULL) {
00459                         dbenv->err(dbenv, ENOMEM, NULL);
00460                         goto err;
00461                 }
00462         if ((data.data = malloc(data.ulen = 1024)) == NULL) {
00463                 dbenv->err(dbenv, ENOMEM, NULL);
00464                 goto err;
00465         }
00466 
00467         if (TXN_ON(dbenv) &&
00468             (ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0)
00469                 goto err;
00470 
00471         /* Get each key/data pair and add them to the database. */
00472         for (recno = 1; !__db_util_interrupted(); ++recno) {
00473                 if (!keyflag) {
00474                         if (checkprint) {
00475                                 if (db_load_dbt_rprint(dbenv, &data))
00476                                         goto err;
00477                         } else {
00478                                 if (db_load_dbt_rdump(dbenv, &data))
00479                                         goto err;
00480                         }
00481                 } else {
00482                         if (checkprint) {
00483                                 if (db_load_dbt_rprint(dbenv, readp))
00484                                         goto err;
00485                                 if (ascii_recno &&
00486                                     db_load_dbt_to_recno(dbenv, readp, &datarecno) != 0)
00487                                         goto err;
00488 
00489                                 if (!G(endodata) && db_load_dbt_rprint(dbenv, &data))
00490                                         goto odd_count;
00491                         } else {
00492                                 if (ascii_recno) {
00493                                         if (db_load_dbt_rrecno(dbenv, readp, hexkeys))
00494                                                 goto err;
00495                                 } else
00496                                         if (db_load_dbt_rdump(dbenv, readp))
00497                                                 goto err;
00498 
00499                                 if (!G(endodata) && db_load_dbt_rdump(dbenv, &data)) {
00500 odd_count:                              dbenv->errx(dbenv,
00501                                             "odd number of key/data pairs");
00502                                         goto err;
00503                                 }
00504                         }
00505                 }
00506                 if (G(endodata))
00507                         break;
00508 retry:          if (txn != NULL)
00509                         if ((ret = dbenv->txn_begin(dbenv, txn, &ctxn, 0)) != 0)
00510                                 goto err;
00511                 switch (ret = dbp->put(dbp, ctxn, writep, &data, put_flags)) {
00512                 case 0:
00513                         if (ctxn != NULL) {
00514                                 if ((ret =
00515                                     ctxn->commit(ctxn, DB_TXN_NOSYNC)) != 0)
00516                                         goto err;
00517                                 ctxn = NULL;
00518                         }
00519                         break;
00520                 case DB_KEYEXIST:
00521                         *existedp = 1;
00522                         dbenv->errx(dbenv,
00523                             "%s: line %d: key already exists, not loaded:",
00524                             name,
00525                             !keyflag ? recno : recno * 2 - 1);
00526 
00527                         (void)dbenv->prdbt(&key,
00528                             checkprint, 0, stderr, __db_pr_callback, 0);
00529                         break;
00530                 case DB_LOCK_DEADLOCK:
00531                         /* If we have a child txn, retry--else it's fatal. */
00532                         if (ctxn != NULL) {
00533                                 if ((ret = ctxn->abort(ctxn)) != 0)
00534                                         goto err;
00535                                 ctxn = NULL;
00536                                 goto retry;
00537                         }
00538                         /* FALLTHROUGH */
00539                 default:
00540                         dbenv->err(dbenv, ret, NULL);
00541                         if (ctxn != NULL) {
00542                                 (void)ctxn->abort(ctxn);
00543                                 ctxn = NULL;
00544                         }
00545                         goto err;
00546                 }
00547                 if (ctxn != NULL) {
00548                         if ((ret = ctxn->abort(ctxn)) != 0)
00549                                 goto err;
00550                         ctxn = NULL;
00551                 }
00552         }
00553 done:   rval = 0;
00554         DB_ASSERT(ctxn == NULL);
00555         if (txn != NULL && (ret = txn->commit(txn, 0)) != 0) {
00556                 txn = NULL;
00557                 goto err;
00558         }
00559 
00560         if (0) {
00561 err:            rval = 1;
00562                 DB_ASSERT(ctxn == NULL);
00563                 if (txn != NULL)
00564                         (void)txn->abort(txn);
00565         }
00566 
00567         /* Close the database. */
00568         if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) {
00569                 dbenv->err(dbenv, ret, "DB->close");
00570                 rval = 1;
00571         }
00572 
00573         if (G(hdrbuf) != NULL)
00574                 free(G(hdrbuf));
00575         G(hdrbuf) = NULL;
00576         /* Free allocated memory. */
00577         if (subdb != NULL)
00578                 free(subdb);
00579         if (dbtype != DB_RECNO && dbtype != DB_QUEUE && key.data != NULL)
00580                 free(key.data);
00581         if (rkey.data != NULL)
00582                 free(rkey.data);
00583         free(data.data);
00584 
00585         return (rval);
00586 }
00587 
00588 /*
00589  * env_create --
00590  *      Create the environment and initialize it for error reporting.
00591  */
00592 int
00593 db_load_env_create(dbenvp, ldg)
00594         DB_ENV **dbenvp;
00595         LDG *ldg;
00596 {
00597         DB_ENV *dbenv;
00598         int ret;
00599 
00600         if ((ret = db_env_create(dbenvp, 0)) != 0) {
00601                 fprintf(stderr,
00602                     "%s: db_env_create: %s\n", ldg->progname, db_strerror(ret));
00603                 return (ret);
00604         }
00605         dbenv = *dbenvp;
00606         dbenv->set_errfile(dbenv, stderr);
00607         dbenv->set_errpfx(dbenv, ldg->progname);
00608         if (ldg->passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
00609             ldg->passwd, DB_ENCRYPT_AES)) != 0) {
00610                 dbenv->err(dbenv, ret, "set_passwd");
00611                 return (ret);
00612         }
00613         if ((ret = db_load_db_init(dbenv, ldg->home, ldg->cache, &ldg->private)) != 0)
00614                 return (ret);
00615         dbenv->app_private = ldg;
00616 
00617         return (0);
00618 }
00619 
00620 /*
00621  * db_init --
00622  *      Initialize the environment.
00623  */
00624 int
00625 db_load_db_init(dbenv, home, cache, is_private)
00626         DB_ENV *dbenv;
00627         char *home;
00628         u_int32_t cache;
00629         int *is_private;
00630 {
00631         u_int32_t flags;
00632         int ret;
00633 
00634         *is_private = 0;
00635         /* We may be loading into a live environment.  Try and join. */
00636         flags = DB_USE_ENVIRON |
00637             DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
00638         if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0)
00639                 return (0);
00640         if (ret == DB_VERSION_MISMATCH)
00641                 goto err;
00642 
00643         /*
00644          * We're trying to load a database.
00645          *
00646          * An environment is required because we may be trying to look at
00647          * databases in directories other than the current one.  We could
00648          * avoid using an environment iff the -h option wasn't specified,
00649          * but that seems like more work than it's worth.
00650          *
00651          * No environment exists (or, at least no environment that includes
00652          * an mpool region exists).  Create one, but make it private so that
00653          * no files are actually created.
00654          */
00655         LF_CLR(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN);
00656         LF_SET(DB_CREATE | DB_PRIVATE);
00657         *is_private = 1;
00658         if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) {
00659                 dbenv->err(dbenv, ret, "set_cachesize");
00660                 return (1);
00661         }
00662         if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0)
00663                 return (0);
00664 
00665         /* An environment is required. */
00666 err:    dbenv->err(dbenv, ret, "DB_ENV->open");
00667         return (1);
00668 }
00669 
00670 #define FLAG(name, value, keyword, flag)                                \
00671         if (strcmp(name, keyword) == 0) {                               \
00672                 switch (*value) {                                       \
00673                 case '1':                                               \
00674                         if ((ret = dbp->set_flags(dbp, flag)) != 0) {   \
00675                                 dbp->err(dbp, ret, "%s: set_flags: %s", \
00676                                     G(progname), name);                 \
00677                                 goto err;                               \
00678                         }                                               \
00679                         break;                                          \
00680                 case '0':                                               \
00681                         break;                                          \
00682                 default:                                                \
00683                         db_load_badnum(dbenv);                                  \
00684                         goto err;                                       \
00685                 }                                                       \
00686                 continue;                                               \
00687         }
00688 #define NUMBER(name, value, keyword, func, t)                           \
00689         if (strcmp(name, keyword) == 0) {                               \
00690                 if ((ret = __db_getlong(dbenv,                          \
00691                     NULL, value, 0, LONG_MAX, &val)) != 0 ||            \
00692                     (ret = dbp->func(dbp, (t)val)) != 0)                \
00693                         goto nameerr;                                   \
00694                 continue;                                               \
00695         }
00696 #define STRING(name, value, keyword, func)                              \
00697         if (strcmp(name, keyword) == 0) {                               \
00698                 if ((ret = dbp->func(dbp, value[0])) != 0)              \
00699                         goto nameerr;                                   \
00700                 continue;                                               \
00701         }
00702 
00703 /*
00704  * configure --
00705  *      Handle command-line configuration options.
00706  */
00707 int
00708 db_load_configure(dbenv, dbp, clp, subdbp, keysp)
00709         DB_ENV *dbenv;
00710         DB *dbp;
00711         char **clp, **subdbp;
00712         int *keysp;
00713 {
00714         long val;
00715         int ret, savech;
00716         char *name, *value;
00717 
00718         for (; (name = *clp) != NULL; *--value = savech, ++clp) {
00719                 if ((value = strchr(name, '=')) == NULL) {
00720                         dbp->errx(dbp,
00721                     "command-line configuration uses name=value format");
00722                         return (1);
00723                 }
00724                 savech = *value;
00725                 *value++ = '\0';
00726 
00727                 if (strcmp(name, "database") == 0 ||
00728                     strcmp(name, "subdatabase") == 0) {
00729                         if (*subdbp != NULL)
00730                                 free(*subdbp);
00731                         if ((*subdbp = strdup(value)) == NULL) {
00732                                 dbp->err(dbp, ENOMEM, NULL);
00733                                 return (1);
00734                         }
00735                         continue;
00736                 }
00737                 if (strcmp(name, "keys") == 0) {
00738                         if (strcmp(value, "1") == 0)
00739                                 *keysp = 1;
00740                         else if (strcmp(value, "0") == 0)
00741                                 *keysp = 0;
00742                         else {
00743                                 db_load_badnum(dbenv);
00744                                 return (1);
00745                         }
00746                         continue;
00747                 }
00748 
00749                 NUMBER(name, value, "bt_minkey", set_bt_minkey, u_int32_t);
00750                 NUMBER(name, value, "db_lorder", set_lorder, int);
00751                 NUMBER(name, value, "db_pagesize", set_pagesize, u_int32_t);
00752                 FLAG(name, value, "chksum", DB_CHKSUM);
00753                 FLAG(name, value, "duplicates", DB_DUP);
00754                 FLAG(name, value, "dupsort", DB_DUPSORT);
00755                 NUMBER(name, value, "h_ffactor", set_h_ffactor, u_int32_t);
00756                 NUMBER(name, value, "h_nelem", set_h_nelem, u_int32_t);
00757                 NUMBER(name, value, "re_len", set_re_len, u_int32_t);
00758                 STRING(name, value, "re_pad", set_re_pad);
00759                 FLAG(name, value, "recnum", DB_RECNUM);
00760                 FLAG(name, value, "renumber", DB_RENUMBER);
00761 
00762                 dbp->errx(dbp,
00763                     "unknown command-line configuration keyword \"%s\"", name);
00764                 return (1);
00765         }
00766         return (0);
00767 
00768 nameerr:
00769         dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value);
00770 err:    return (1);
00771 }
00772 
00773 /*
00774  * rheader --
00775  *      Read the header message.
00776  */
00777 int
00778 db_load_rheader(dbenv, dbp, dbtypep, subdbp, checkprintp, keysp)
00779         DB_ENV *dbenv;
00780         DB *dbp;
00781         DBTYPE *dbtypep;
00782         char **subdbp;
00783         int *checkprintp, *keysp;
00784 {
00785         size_t buflen, linelen, start;
00786         long val;
00787         int ch, first, hdr, ret;
00788         char *buf, *name, *p, *value;
00789 
00790         *dbtypep = DB_UNKNOWN;
00791         *checkprintp = 0;
00792         name = NULL;
00793 
00794         /*
00795          * We start with a smallish buffer;  most headers are small.
00796          * We may need to realloc it for a large subdatabase name.
00797          */
00798         buflen = 4096;
00799         if (G(hdrbuf) == NULL) {
00800                 hdr = 0;
00801                 if ((buf = malloc(buflen)) == NULL)
00802                         goto memerr;
00803                 G(hdrbuf) = buf;
00804                 G(origline) = G(lineno);
00805         } else {
00806                 hdr = 1;
00807                 buf = G(hdrbuf);
00808                 G(lineno) = G(origline);
00809         }
00810 
00811         start = 0;
00812         for (first = 1;; first = 0) {
00813                 ++G(lineno);
00814 
00815                 /* Read a line, which may be of arbitrary length, into buf. */
00816                 linelen = 0;
00817                 buf = &G(hdrbuf)[start];
00818                 if (hdr == 0) {
00819                         for (;;) {
00820                                 if ((ch = getchar()) == EOF) {
00821                                         if (!first || ferror(stdin))
00822                                                 goto badfmt;
00823                                         G(endofile) = 1;
00824                                         break;
00825                                 }
00826 
00827                                 /*
00828                                  * If the buffer is too small, double it.
00829                                  */
00830                                 if (linelen + start == buflen) {
00831                                         G(hdrbuf) =
00832                                             realloc(G(hdrbuf), buflen *= 2);
00833                                         if (G(hdrbuf) == NULL)
00834                                                 goto memerr;
00835                                         buf = &G(hdrbuf)[start];
00836                                 }
00837 
00838                                 if (ch == '\n')
00839                                         break;
00840 
00841                                 buf[linelen++] = ch;
00842                         }
00843                         if (G(endofile) == 1)
00844                                 break;
00845                         buf[linelen++] = '\0';
00846                 } else
00847                         linelen = strlen(buf) + 1;
00848                 start += linelen;
00849 
00850                 if (name != NULL) {
00851                         free(name);
00852                         name = NULL;
00853                 }
00854                 /* If we don't see the expected information, it's an error. */
00855                 if ((name = strdup(buf)) == NULL)
00856                         goto memerr;
00857                 if ((p = strchr(name, '=')) == NULL)
00858                         goto badfmt;
00859                 *p++ = '\0';
00860 
00861                 value = p--;
00862 
00863                 if (name[0] == '\0' || value[0] == '\0')
00864                         goto badfmt;
00865 
00866                 if (strcmp(name, "HEADER") == 0)
00867                         break;
00868                 if (strcmp(name, "VERSION") == 0) {
00869                         /*
00870                          * Version 1 didn't have a "VERSION" header line.  We
00871                          * only support versions 1, 2, and 3 of the dump format.
00872                          */
00873                         G(version) = atoi(value);
00874 
00875                         if (G(version) > 3) {
00876                                 dbp->errx(dbp,
00877                                     "line %lu: VERSION %d is unsupported",
00878                                     G(lineno), G(version));
00879                                 goto err;
00880                         }
00881                         continue;
00882                 }
00883                 if (strcmp(name, "format") == 0) {
00884                         if (strcmp(value, "bytevalue") == 0) {
00885                                 *checkprintp = 0;
00886                                 continue;
00887                         }
00888                         if (strcmp(value, "print") == 0) {
00889                                 *checkprintp = 1;
00890                                 continue;
00891                         }
00892                         goto badfmt;
00893                 }
00894                 if (strcmp(name, "type") == 0) {
00895                         if (strcmp(value, "btree") == 0) {
00896                                 *dbtypep = DB_BTREE;
00897                                 continue;
00898                         }
00899                         if (strcmp(value, "hash") == 0) {
00900                                 *dbtypep = DB_HASH;
00901                                 continue;
00902                         }
00903                         if (strcmp(value, "recno") == 0) {
00904                                 *dbtypep = DB_RECNO;
00905                                 continue;
00906                         }
00907                         if (strcmp(value, "queue") == 0) {
00908                                 *dbtypep = DB_QUEUE;
00909                                 continue;
00910                         }
00911                         dbp->errx(dbp, "line %lu: unknown type", G(lineno));
00912                         goto err;
00913                 }
00914                 if (strcmp(name, "database") == 0 ||
00915                     strcmp(name, "subdatabase") == 0) {
00916                         if ((ret = db_load_convprintable(dbenv, value, subdbp)) != 0) {
00917                                 dbp->err(dbp, ret, "error reading db name");
00918                                 goto err;
00919                         }
00920                         continue;
00921                 }
00922                 if (strcmp(name, "keys") == 0) {
00923                         if (strcmp(value, "1") == 0)
00924                                 *keysp = 1;
00925                         else if (strcmp(value, "0") == 0)
00926                                 *keysp = 0;
00927                         else {
00928                                 db_load_badnum(dbenv);
00929                                 goto err;
00930                         }
00931                         continue;
00932                 }
00933 
00934 #ifdef notyet
00935                 NUMBER(name, value, "bt_maxkey", set_bt_maxkey, u_int32_t);
00936 #endif
00937                 NUMBER(name, value, "bt_minkey", set_bt_minkey, u_int32_t);
00938                 NUMBER(name, value, "db_lorder", set_lorder, int);
00939                 NUMBER(name, value, "db_pagesize", set_pagesize, u_int32_t);
00940                 NUMBER(name, value, "extentsize", set_q_extentsize, u_int32_t);
00941                 FLAG(name, value, "chksum", DB_CHKSUM);
00942                 FLAG(name, value, "duplicates", DB_DUP);
00943                 FLAG(name, value, "dupsort", DB_DUPSORT);
00944                 NUMBER(name, value, "h_ffactor", set_h_ffactor, u_int32_t);
00945                 NUMBER(name, value, "h_nelem", set_h_nelem, u_int32_t);
00946                 NUMBER(name, value, "re_len", set_re_len, u_int32_t);
00947                 STRING(name, value, "re_pad", set_re_pad);
00948                 FLAG(name, value, "recnum", DB_RECNUM);
00949                 FLAG(name, value, "renumber", DB_RENUMBER);
00950 
00951                 dbp->errx(dbp,
00952                     "unknown input-file header configuration keyword \"%s\"",
00953                     name);
00954                 goto err;
00955         }
00956         ret = 0;
00957 
00958         if (0) {
00959 nameerr:        dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value);
00960                 ret = 1;
00961         }
00962         if (0) {
00963 badfmt:         dbp->errx(dbp, "line %lu: unexpected format", G(lineno));
00964                 ret = 1;
00965         }
00966         if (0) {
00967 memerr:         dbp->errx(dbp, "unable to allocate memory");
00968 err:            ret = 1;
00969         }
00970         if (name != NULL)
00971                 free(name);
00972         return (ret);
00973 }
00974 
00975 /*
00976  * convprintable --
00977  *      Convert a printable-encoded string into a newly allocated string.
00978  *
00979  * In an ideal world, this would probably share code with dbt_rprint, but
00980  * that's set up to read character-by-character (to avoid large memory
00981  * allocations that aren't likely to be a problem here), and this has fewer
00982  * special cases to deal with.
00983  *
00984  * Note that despite the printable encoding, the char * interface to this
00985  * function (which is, not coincidentally, also used for database naming)
00986  * means that outstr cannot contain any nuls.
00987  */
00988 int
00989 db_load_convprintable(dbenv, instr, outstrp)
00990         DB_ENV *dbenv;
00991         char *instr, **outstrp;
00992 {
00993         char c, *outstr;
00994         int e1, e2;
00995 
00996         /*
00997          * Just malloc a string big enough for the whole input string;
00998          * the output string will be smaller (or of equal length).
00999          */
01000         if ((outstr = malloc(strlen(instr) + 1)) == NULL)
01001                 return (ENOMEM);
01002 
01003         *outstrp = outstr;
01004 
01005         e1 = e2 = 0;
01006         for ( ; *instr != '\0'; instr++)
01007                 if (*instr == '\\') {
01008                         if (*++instr == '\\') {
01009                                 *outstr++ = '\\';
01010                                 continue;
01011                         }
01012                         c = db_load_digitize(dbenv, *instr, &e1) << 4;
01013                         c |= db_load_digitize(dbenv, *++instr, &e2);
01014                         if (e1 || e2) {
01015                                 db_load_badend(dbenv);
01016                                 return (EINVAL);
01017                         }
01018 
01019                         *outstr++ = c;
01020                 } else
01021                         *outstr++ = *instr;
01022 
01023         *outstr = '\0';
01024 
01025         return (0);
01026 }
01027 
01028 /*
01029  * dbt_rprint --
01030  *      Read a printable line into a DBT structure.
01031  */
01032 int
01033 db_load_dbt_rprint(dbenv, dbtp)
01034         DB_ENV *dbenv;
01035         DBT *dbtp;
01036 {
01037         u_int32_t len;
01038         u_int8_t *p;
01039         int c1, c2, e, escape, first;
01040         char buf[32];
01041 
01042         ++G(lineno);
01043 
01044         first = 1;
01045         e = escape = 0;
01046         for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) {
01047                 if (c1 == EOF) {
01048                         if (len == 0) {
01049                                 G(endofile) = G(endodata) = 1;
01050                                 return (0);
01051                         }
01052                         db_load_badend(dbenv);
01053                         return (1);
01054                 }
01055                 if (first) {
01056                         first = 0;
01057                         if (G(version) > 1) {
01058                                 if (c1 != ' ') {
01059                                         buf[0] = c1;
01060                                         if (fgets(buf + 1,
01061                                             sizeof(buf) - 1, stdin) == NULL ||
01062                                             strcmp(buf, "DATA=END\n") != 0) {
01063                                                 db_load_badend(dbenv);
01064                                                 return (1);
01065                                         }
01066                                         G(endodata) = 1;
01067                                         return (0);
01068                                 }
01069                                 continue;
01070                         }
01071                 }
01072                 if (escape) {
01073                         if (c1 != '\\') {
01074                                 if ((c2 = getchar()) == EOF) {
01075                                         db_load_badend(dbenv);
01076                                         return (1);
01077                                 }
01078                                 c1 = db_load_digitize(dbenv,
01079                                     c1, &e) << 4 | db_load_digitize(dbenv, c2, &e);
01080                                 if (e)
01081                                         return (1);
01082                         }
01083                         escape = 0;
01084                 } else
01085                         if (c1 == '\\') {
01086                                 escape = 1;
01087                                 continue;
01088                         }
01089                 if (len >= dbtp->ulen - 10) {
01090                         dbtp->ulen *= 2;
01091                         if ((dbtp->data =
01092                             realloc(dbtp->data, dbtp->ulen)) == NULL) {
01093                                 dbenv->err(dbenv, ENOMEM, NULL);
01094                                 return (1);
01095                         }
01096                         p = (u_int8_t *)dbtp->data + len;
01097                 }
01098                 ++len;
01099                 *p++ = c1;
01100         }
01101         dbtp->size = len;
01102 
01103         return (0);
01104 }
01105 
01106 /*
01107  * dbt_rdump --
01108  *      Read a byte dump line into a DBT structure.
01109  */
01110 int
01111 db_load_dbt_rdump(dbenv, dbtp)
01112         DB_ENV *dbenv;
01113         DBT *dbtp;
01114 {
01115         u_int32_t len;
01116         u_int8_t *p;
01117         int c1, c2, e, first;
01118         char buf[32];
01119 
01120         ++G(lineno);
01121 
01122         first = 1;
01123         e = 0;
01124         for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) {
01125                 if (c1 == EOF) {
01126                         if (len == 0) {
01127                                 G(endofile) = G(endodata) = 1;
01128                                 return (0);
01129                         }
01130                         db_load_badend(dbenv);
01131                         return (1);
01132                 }
01133                 if (first) {
01134                         first = 0;
01135                         if (G(version) > 1) {
01136                                 if (c1 != ' ') {
01137                                         buf[0] = c1;
01138                                         if (fgets(buf + 1,
01139                                             sizeof(buf) - 1, stdin) == NULL ||
01140                                             strcmp(buf, "DATA=END\n") != 0) {
01141                                                 db_load_badend(dbenv);
01142                                                 return (1);
01143                                         }
01144                                         G(endodata) = 1;
01145                                         return (0);
01146                                 }
01147                                 continue;
01148                         }
01149                 }
01150                 if ((c2 = getchar()) == EOF) {
01151                         db_load_badend(dbenv);
01152                         return (1);
01153                 }
01154                 if (len >= dbtp->ulen - 10) {
01155                         dbtp->ulen *= 2;
01156                         if ((dbtp->data =
01157                             realloc(dbtp->data, dbtp->ulen)) == NULL) {
01158                                 dbenv->err(dbenv, ENOMEM, NULL);
01159                                 return (1);
01160                         }
01161                         p = (u_int8_t *)dbtp->data + len;
01162                 }
01163                 ++len;
01164                 *p++ = db_load_digitize(dbenv, c1, &e) << 4 | db_load_digitize(dbenv, c2, &e);
01165                 if (e)
01166                         return (1);
01167         }
01168         dbtp->size = len;
01169 
01170         return (0);
01171 }
01172 
01173 /*
01174  * dbt_rrecno --
01175  *      Read a record number dump line into a DBT structure.
01176  */
01177 int
01178 db_load_dbt_rrecno(dbenv, dbtp, ishex)
01179         DB_ENV *dbenv;
01180         DBT *dbtp;
01181         int ishex;
01182 {
01183         char buf[32], *p, *q;
01184         u_long recno;
01185 
01186         ++G(lineno);
01187 
01188         if (fgets(buf, sizeof(buf), stdin) == NULL) {
01189                 G(endofile) = G(endodata) = 1;
01190                 return (0);
01191         }
01192 
01193         if (strcmp(buf, "DATA=END\n") == 0) {
01194                 G(endodata) = 1;
01195                 return (0);
01196         }
01197 
01198         if (buf[0] != ' ')
01199                 goto bad;
01200 
01201         /*
01202          * If we're expecting a hex key, do an in-place conversion
01203          * of hex to straight ASCII before calling __db_getulong().
01204          */
01205         if (ishex) {
01206                 for (p = q = buf + 1; *q != '\0' && *q != '\n';) {
01207                         /*
01208                          * 0-9 in hex are 0x30-0x39, so this is easy.
01209                          * We should alternate between 3's and [0-9], and
01210                          * if the [0-9] are something unexpected,
01211                          * __db_getulong will fail, so we only need to catch
01212                          * end-of-string conditions.
01213                          */
01214                         if (*q++ != '3')
01215                                 goto bad;
01216                         if (*q == '\n' || *q == '\0')
01217                                 goto bad;
01218                         *p++ = *q++;
01219                 }
01220                 *p = '\0';
01221         }
01222 
01223         if (__db_getulong(dbenv, G(progname), buf + 1, 0, 0, &recno)) {
01224 bad:            db_load_badend(dbenv);
01225                 return (1);
01226         }
01227 
01228         *((db_recno_t *)dbtp->data) = recno;
01229         dbtp->size = sizeof(db_recno_t);
01230         return (0);
01231 }
01232 
01233 int
01234 db_load_dbt_to_recno(dbenv, dbt, recnop)
01235         DB_ENV *dbenv;
01236         DBT *dbt;
01237         db_recno_t *recnop;
01238 {
01239         char buf[32];                           /* Large enough for 2^64. */
01240 
01241         memcpy(buf, dbt->data, dbt->size);
01242         buf[dbt->size] = '\0';
01243 
01244         return (__db_getulong(dbenv, G(progname), buf, 0, 0, (u_long *)recnop));
01245 }
01246 
01247 /*
01248  * digitize --
01249  *      Convert a character to an integer.
01250  */
01251 int
01252 db_load_digitize(dbenv, c, errorp)
01253         DB_ENV *dbenv;
01254         int c, *errorp;
01255 {
01256         switch (c) {                    /* Don't depend on ASCII ordering. */
01257         case '0': return (0);
01258         case '1': return (1);
01259         case '2': return (2);
01260         case '3': return (3);
01261         case '4': return (4);
01262         case '5': return (5);
01263         case '6': return (6);
01264         case '7': return (7);
01265         case '8': return (8);
01266         case '9': return (9);
01267         case 'a': return (10);
01268         case 'b': return (11);
01269         case 'c': return (12);
01270         case 'd': return (13);
01271         case 'e': return (14);
01272         case 'f': return (15);
01273         default:                        /* Not possible. */
01274                 break;
01275         }
01276 
01277         dbenv->errx(dbenv, "unexpected hexadecimal value");
01278         *errorp = 1;
01279 
01280         return (0);
01281 }
01282 
01283 /*
01284  * badnum --
01285  *      Display the bad number message.
01286  */
01287 void
01288 db_load_badnum(dbenv)
01289         DB_ENV *dbenv;
01290 {
01291         dbenv->errx(dbenv,
01292             "boolean name=value pairs require a value of 0 or 1");
01293 }
01294 
01295 /*
01296  * badend --
01297  *      Display the bad end to input message.
01298  */
01299 void
01300 db_load_badend(dbenv)
01301         DB_ENV *dbenv;
01302 {
01303         dbenv->errx(dbenv, "unexpected end of input data or key/data pair");
01304 }
01305 
01306 /*
01307  * usage --
01308  *      Display the usage message.
01309  */
01310 int
01311 db_load_usage()
01312 {
01313         (void)fprintf(stderr, "usage: %s %s\n\t%s\n", progname,
01314             "[-nTV] [-c name=value] [-f file]",
01315     "[-h home] [-P password] [-t btree | hash | recno | queue] db_file");
01316         (void)fprintf(stderr, "usage: %s %s\n",
01317             progname, "-r lsn | fileid [-h home] [-P password] db_file");
01318         return (EXIT_FAILURE);
01319 }
01320 
01321 int
01322 db_load_version_check()
01323 {
01324         int v_major, v_minor, v_patch;
01325 
01326         /* Make sure we're loaded with the right version of the DB library. */
01327         (void)db_version(&v_major, &v_minor, &v_patch);
01328         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
01329                 fprintf(stderr,
01330         "%s: version %d.%d doesn't match library version %d.%d\n",
01331                     progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
01332                     v_major, v_minor);
01333                 return (EXIT_FAILURE);
01334         }
01335         return (0);
01336 }

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