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

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