1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_load.c,v 12.26 2008/01/11 20:49:57 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/db_am.h" 14 15#ifndef lint 16static const char copyright[] = 17 "Copyright (c) 1996,2008 Oracle. All rights reserved.\n"; 18#endif 19 20typedef struct { /* XXX: Globals. */ 21 const char *progname; /* Program name. */ 22 char *hdrbuf; /* Input file header. */ 23 u_long lineno; /* Input file line number. */ 24 u_long origline; /* Original file line number. */ 25 int endodata; /* Reached the end of a database. */ 26 int endofile; /* Reached the end of the input. */ 27 int version; /* Input version. */ 28 char *home; /* Env home. */ 29 char *passwd; /* Env passwd. */ 30 int private; /* Private env. */ 31 u_int32_t cache; /* Env cache size. */ 32} LDG; 33 34int db_load_badend __P((DB_ENV *)); 35void db_load_badnum __P((DB_ENV *)); 36int db_load_configure __P((DB_ENV *, DB *, char **, char **, int *)); 37int db_load_convprintable __P((DB_ENV *, char *, char **)); 38int db_load_db_init __P((DB_ENV *, char *, u_int32_t, int *)); 39int db_load_dbt_rdump __P((DB_ENV *, DBT *)); 40int db_load_dbt_rprint __P((DB_ENV *, DBT *)); 41int db_load_dbt_rrecno __P((DB_ENV *, DBT *, int)); 42int db_load_dbt_to_recno __P((DB_ENV *, DBT *, db_recno_t *)); 43int db_load_env_create __P((DB_ENV **, LDG *)); 44int db_load_load __P((DB_ENV *, char *, DBTYPE, char **, u_int, LDG *, int *)); 45int db_load_main __P((int, char *[])); 46int db_load_rheader __P((DB_ENV *, DB *, DBTYPE *, char **, int *, int *)); 47int db_load_usage __P((void)); 48int db_load_version_check __P((void)); 49 50const char *progname; 51 52#define G(f) ((LDG *)dbenv->app_private)->f 53 54 /* Flags to the load function. */ 55#define LDF_NOHEADER 0x01 /* No dump header. */ 56#define LDF_NOOVERWRITE 0x02 /* Don't overwrite existing rows. */ 57#define LDF_PASSWORD 0x04 /* Encrypt created databases. */ 58 59int 60db_load(args) 61 char *args; 62{ 63 int argc; 64 char **argv; 65 66 __db_util_arg("db_load", args, &argc, &argv); 67 return (db_load_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS); 68} 69 70#include <stdio.h> 71#define ERROR_RETURN ERROR 72 73int 74db_load_main(argc, argv) 75 int argc; 76 char *argv[]; 77{ 78 enum { NOTSET, FILEID_RESET, LSN_RESET, STANDARD_LOAD } mode; 79 extern char *optarg; 80 extern int optind, __db_getopt_reset; 81 DBTYPE dbtype; 82 DB_ENV *dbenv; 83 LDG ldg; 84 u_int ldf; 85 int ch, existed, exitval, ret; 86 char **clist, **clp; 87 88 if ((progname = __db_rpath(argv[0])) == NULL) 89 progname = argv[0]; 90 else 91 ++progname; 92 93 if ((ret = db_load_version_check()) != 0) 94 return (ret); 95 96 ldg.progname = progname; 97 ldg.lineno = 0; 98 ldg.endodata = ldg.endofile = 0; 99 ldg.version = 1; 100 ldg.cache = MEGABYTE; 101 ldg.hdrbuf = NULL; 102 ldg.home = NULL; 103 ldg.passwd = NULL; 104 105 mode = NOTSET; 106 ldf = 0; 107 exitval = existed = 0; 108 dbtype = DB_UNKNOWN; 109 110 /* Allocate enough room for configuration arguments. */ 111 if ((clp = clist = 112 (char **)calloc((size_t)argc + 1, sizeof(char *))) == NULL) { 113 fprintf(stderr, "%s: %s\n", ldg.progname, strerror(ENOMEM)); 114 return (EXIT_FAILURE); 115 } 116 117 /* 118 * There are two modes for db_load: -r and everything else. The -r 119 * option zeroes out the database LSN's or resets the file ID, it 120 * doesn't really "load" a new database. The functionality is in 121 * db_load because we don't have a better place to put it, and we 122 * don't want to create a new utility for just that functionality. 123 */ 124 __db_getopt_reset = 1; 125 while ((ch = getopt(argc, argv, "c:f:h:nP:r:Tt:V")) != EOF) 126 switch (ch) { 127 case 'c': 128 if (mode != NOTSET && mode != STANDARD_LOAD) 129 return (db_load_usage()); 130 mode = STANDARD_LOAD; 131 132 *clp++ = optarg; 133 break; 134 case 'f': 135 if (mode != NOTSET && mode != STANDARD_LOAD) 136 return (db_load_usage()); 137 mode = STANDARD_LOAD; 138 139 if (freopen(optarg, "r", stdin) == NULL) { 140 fprintf(stderr, "%s: %s: reopen: %s\n", 141 ldg.progname, optarg, strerror(errno)); 142 return (EXIT_FAILURE); 143 } 144 break; 145 case 'h': 146 ldg.home = optarg; 147 break; 148 case 'n': 149 if (mode != NOTSET && mode != STANDARD_LOAD) 150 return (db_load_usage()); 151 mode = STANDARD_LOAD; 152 153 ldf |= LDF_NOOVERWRITE; 154 break; 155 case 'P': 156 ldg.passwd = strdup(optarg); 157 memset(optarg, 0, strlen(optarg)); 158 if (ldg.passwd == NULL) { 159 fprintf(stderr, "%s: strdup: %s\n", 160 ldg.progname, strerror(errno)); 161 return (EXIT_FAILURE); 162 } 163 ldf |= LDF_PASSWORD; 164 break; 165 case 'r': 166 if (mode == STANDARD_LOAD) 167 return (db_load_usage()); 168 if (strcmp(optarg, "lsn") == 0) 169 mode = LSN_RESET; 170 else if (strcmp(optarg, "fileid") == 0) 171 mode = FILEID_RESET; 172 else 173 return (db_load_usage()); 174 break; 175 case 'T': 176 if (mode != NOTSET && mode != STANDARD_LOAD) 177 return (db_load_usage()); 178 mode = STANDARD_LOAD; 179 180 ldf |= LDF_NOHEADER; 181 break; 182 case 't': 183 if (mode != NOTSET && mode != STANDARD_LOAD) 184 return (db_load_usage()); 185 mode = STANDARD_LOAD; 186 187 if (strcmp(optarg, "btree") == 0) { 188 dbtype = DB_BTREE; 189 break; 190 } 191 if (strcmp(optarg, "hash") == 0) { 192 dbtype = DB_HASH; 193 break; 194 } 195 if (strcmp(optarg, "recno") == 0) { 196 dbtype = DB_RECNO; 197 break; 198 } 199 if (strcmp(optarg, "queue") == 0) { 200 dbtype = DB_QUEUE; 201 break; 202 } 203 return (db_load_usage()); 204 case 'V': 205 printf("%s\n", db_version(NULL, NULL, NULL)); 206 return (EXIT_SUCCESS); 207 case '?': 208 default: 209 return (db_load_usage()); 210 } 211 argc -= optind; 212 argv += optind; 213 214 if (argc != 1) 215 return (db_load_usage()); 216 217 /* Handle possible interruptions. */ 218 __db_util_siginit(); 219 220 /* 221 * Create an environment object initialized for error reporting, and 222 * then open it. 223 */ 224 if (db_load_env_create(&dbenv, &ldg) != 0) 225 goto shutdown; 226 227 /* If we're resetting the LSNs, that's an entirely separate path. */ 228 switch (mode) { 229 case FILEID_RESET: 230 exitval = dbenv->fileid_reset( 231 dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0); 232 break; 233 case LSN_RESET: 234 exitval = dbenv->lsn_reset( 235 dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0); 236 break; 237 case NOTSET: 238 case STANDARD_LOAD: 239 while (!ldg.endofile) 240 if (db_load_load(dbenv, argv[0], dbtype, clist, ldf, 241 &ldg, &existed) != 0) 242 goto shutdown; 243 break; 244 } 245 246 if (0) { 247shutdown: exitval = 1; 248 } 249 if ((ret = dbenv->close(dbenv, 0)) != 0) { 250 exitval = 1; 251 fprintf(stderr, 252 "%s: dbenv->close: %s\n", ldg.progname, db_strerror(ret)); 253 } 254 255 /* Resend any caught signal. */ 256 __db_util_sigresend(); 257 free(clist); 258 if (ldg.passwd != NULL) 259 free(ldg.passwd); 260 261 /* 262 * Return 0 on success, 1 if keys existed already, and 2 on failure. 263 * 264 * Technically, this is wrong, because exit of anything other than 265 * 0 is implementation-defined by the ANSI C standard. I don't see 266 * any good solutions that don't involve API changes. 267 */ 268 return (exitval == 0 ? (existed == 0 ? 0 : 1) : 2); 269} 270 271/* 272 * load -- 273 * Load a database. 274 */ 275int 276db_load_load(dbenv, name, argtype, clist, flags, ldg, existedp) 277 DB_ENV *dbenv; 278 char *name, **clist; 279 DBTYPE argtype; 280 u_int flags; 281 LDG *ldg; 282 int *existedp; 283{ 284 DB *dbp; 285 DBT key, rkey, data, *readp, *writep; 286 DBTYPE dbtype; 287 DB_TXN *ctxn, *txn; 288 db_recno_t recno, datarecno; 289 u_int32_t put_flags; 290 int ascii_recno, checkprint, hexkeys, keyflag, keys, resize, ret, rval; 291 char *subdb; 292 293 put_flags = LF_ISSET(LDF_NOOVERWRITE) ? DB_NOOVERWRITE : 0; 294 G(endodata) = 0; 295 296 subdb = NULL; 297 ctxn = txn = NULL; 298 memset(&key, 0, sizeof(DBT)); 299 memset(&data, 0, sizeof(DBT)); 300 memset(&rkey, 0, sizeof(DBT)); 301 302retry_db: 303 dbtype = DB_UNKNOWN; 304 keys = -1; 305 hexkeys = -1; 306 keyflag = -1; 307 308 /* Create the DB object. */ 309 if ((ret = db_create(&dbp, dbenv, 0)) != 0) { 310 dbenv->err(dbenv, ret, "db_create"); 311 goto err; 312 } 313 314 /* Read the header -- if there's no header, we expect flat text. */ 315 if (LF_ISSET(LDF_NOHEADER)) { 316 checkprint = 1; 317 dbtype = argtype; 318 } else { 319 if (db_load_rheader(dbenv, 320 dbp, &dbtype, &subdb, &checkprint, &keys) != 0) 321 goto err; 322 if (G(endofile)) 323 goto done; 324 } 325 326 /* 327 * Apply command-line configuration changes. (We apply command-line 328 * configuration changes to all databases that are loaded, e.g., all 329 * subdatabases.) 330 */ 331 if (db_load_configure(dbenv, dbp, clist, &subdb, &keyflag)) 332 goto err; 333 334 if (keys != 1) { 335 if (keyflag == 1) { 336 dbp->err(dbp, EINVAL, "No keys specified in file"); 337 goto err; 338 } 339 } 340 else if (keyflag == 0) { 341 dbp->err(dbp, EINVAL, "Keys specified in file"); 342 goto err; 343 } 344 else 345 keyflag = 1; 346 347 if (dbtype == DB_BTREE || dbtype == DB_HASH) { 348 if (keyflag == 0) 349 dbp->err(dbp, 350 EINVAL, "Btree and Hash must specify keys"); 351 else 352 keyflag = 1; 353 } 354 355 if (argtype != DB_UNKNOWN) { 356 357 if (dbtype == DB_RECNO || dbtype == DB_QUEUE) 358 if (keyflag != 1 && argtype != DB_RECNO && 359 argtype != DB_QUEUE) { 360 dbenv->errx(dbenv, 361 "improper database type conversion specified"); 362 goto err; 363 } 364 dbtype = argtype; 365 } 366 367 if (dbtype == DB_UNKNOWN) { 368 dbenv->errx(dbenv, "no database type specified"); 369 goto err; 370 } 371 372 if (keyflag == -1) 373 keyflag = 0; 374 375 /* 376 * Recno keys have only been printed in hexadecimal starting 377 * with db_dump format version 3 (DB 3.2). 378 * 379 * !!! 380 * Note that version is set in db_load_rheader(), which must be called before 381 * this assignment. 382 */ 383 hexkeys = (G(version) >= 3 && keyflag == 1 && checkprint == 0); 384 385 if (keyflag == 1 && (dbtype == DB_RECNO || dbtype == DB_QUEUE)) 386 ascii_recno = 1; 387 else 388 ascii_recno = 0; 389 390 /* If configured with a password, encrypt databases we create. */ 391 if (LF_ISSET(LDF_PASSWORD) && 392 (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) { 393 dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT"); 394 goto err; 395 } 396 397#if 0 398 Set application-specific btree comparison or hash functions here. 399 For example: 400 401 if ((ret = dbp->set_bt_compare(dbp, local_comparison_func)) != 0) { 402 dbp->err(dbp, ret, "DB->set_bt_compare"); 403 goto err; 404 } 405 if ((ret = dbp->set_h_hash(dbp, local_hash_func)) != 0) { 406 dbp->err(dbp, ret, "DB->set_h_hash"); 407 goto err; 408 } 409#endif 410 411 /* Open the DB file. */ 412 if ((ret = dbp->open(dbp, NULL, name, subdb, dbtype, 413 DB_CREATE | (TXN_ON(dbenv->env) ? DB_AUTO_COMMIT : 0), 414 DB_MODE_666)) != 0) { 415 dbp->err(dbp, ret, "DB->open: %s", name); 416 goto err; 417 } 418 if (ldg->private != 0) { 419 if ((ret = __db_util_cache(dbp, &ldg->cache, &resize)) != 0) 420 goto err; 421 if (resize) { 422 if ((ret = dbp->close(dbp, 0)) != 0) 423 goto err; 424 dbp = NULL; 425 if ((ret = dbenv->close(dbenv, 0)) != 0) 426 goto err; 427 if ((ret = db_load_env_create(&dbenv, ldg)) != 0) 428 goto err; 429 goto retry_db; 430 } 431 } 432 433 /* Initialize the key/data pair. */ 434 readp = writep = &key; 435 if (dbtype == DB_RECNO || dbtype == DB_QUEUE) { 436 key.size = sizeof(recno); 437 if (keyflag) { 438 key.data = &datarecno; 439 if (checkprint) { 440 readp = &rkey; 441 goto key_data; 442 } 443 } else 444 key.data = &recno; 445 } else 446key_data: if ((readp->data = malloc(readp->ulen = 1024)) == NULL) { 447 dbenv->err(dbenv, ENOMEM, NULL); 448 goto err; 449 } 450 if ((data.data = malloc(data.ulen = 1024)) == NULL) { 451 dbenv->err(dbenv, ENOMEM, NULL); 452 goto err; 453 } 454 455 if (TXN_ON(dbenv->env) && 456 (ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) 457 goto err; 458 459 /* Get each key/data pair and add them to the database. */ 460 for (recno = 1; !__db_util_interrupted(); ++recno) { 461 if (!keyflag) { 462 if (checkprint) { 463 if (db_load_dbt_rprint(dbenv, &data)) 464 goto err; 465 } else { 466 if (db_load_dbt_rdump(dbenv, &data)) 467 goto err; 468 } 469 } else { 470 if (checkprint) { 471 if (db_load_dbt_rprint(dbenv, readp)) 472 goto err; 473 if (ascii_recno && 474 db_load_dbt_to_recno(dbenv, readp, &datarecno) != 0) 475 goto err; 476 477 if (!G(endodata) && db_load_dbt_rprint(dbenv, &data)) 478 goto odd_count; 479 } else { 480 if (ascii_recno) { 481 if (db_load_dbt_rrecno(dbenv, readp, hexkeys)) 482 goto err; 483 } else 484 if (db_load_dbt_rdump(dbenv, readp)) 485 goto err; 486 487 if (!G(endodata) && db_load_dbt_rdump(dbenv, &data)) { 488odd_count: dbenv->errx(dbenv, 489 "odd number of key/data pairs"); 490 goto err; 491 } 492 } 493 } 494 if (G(endodata)) 495 break; 496retry: if (txn != NULL) 497 if ((ret = dbenv->txn_begin(dbenv, txn, &ctxn, 0)) != 0) 498 goto err; 499 switch (ret = dbp->put(dbp, ctxn, writep, &data, put_flags)) { 500 case 0: 501 if (ctxn != NULL) { 502 if ((ret = 503 ctxn->commit(ctxn, DB_TXN_NOSYNC)) != 0) 504 goto err; 505 ctxn = NULL; 506 } 507 break; 508 case DB_KEYEXIST: 509 *existedp = 1; 510 dbenv->errx(dbenv, 511 "%s: line %d: key already exists, not loaded:", 512 name, 513 !keyflag ? recno : recno * 2 - 1); 514 515 (void)dbenv->prdbt(&key, 516 checkprint, 0, stderr, __db_pr_callback, 0); 517 break; 518 case DB_LOCK_DEADLOCK: 519 /* If we have a child txn, retry--else it's fatal. */ 520 if (ctxn != NULL) { 521 if ((ret = ctxn->abort(ctxn)) != 0) 522 goto err; 523 ctxn = NULL; 524 goto retry; 525 } 526 /* FALLTHROUGH */ 527 default: 528 dbenv->err(dbenv, ret, NULL); 529 if (ctxn != NULL) { 530 (void)ctxn->abort(ctxn); 531 ctxn = NULL; 532 } 533 goto err; 534 } 535 if (ctxn != NULL) { 536 if ((ret = ctxn->abort(ctxn)) != 0) 537 goto err; 538 ctxn = NULL; 539 } 540 } 541done: rval = 0; 542 if (txn != NULL && (ret = txn->commit(txn, 0)) != 0) { 543 txn = NULL; 544 goto err; 545 } 546 547 if (0) { 548err: rval = 1; 549 if (txn != NULL) 550 (void)txn->abort(txn); 551 } 552 553 /* Close the database. */ 554 if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) { 555 dbenv->err(dbenv, ret, "DB->close"); 556 rval = 1; 557 } 558 559 if (G(hdrbuf) != NULL) 560 free(G(hdrbuf)); 561 G(hdrbuf) = NULL; 562 /* Free allocated memory. */ 563 if (subdb != NULL) 564 free(subdb); 565 if (dbtype != DB_RECNO && dbtype != DB_QUEUE && key.data != NULL) 566 free(key.data); 567 if (rkey.data != NULL) 568 free(rkey.data); 569 free(data.data); 570 571 return (rval); 572} 573 574/* 575 * env_create -- 576 * Create the environment and initialize it for error reporting. 577 */ 578int 579db_load_env_create(dbenvp, ldg) 580 DB_ENV **dbenvp; 581 LDG *ldg; 582{ 583 DB_ENV *dbenv; 584 int ret; 585 586 if ((ret = db_env_create(dbenvp, 0)) != 0) { 587 fprintf(stderr, 588 "%s: db_env_create: %s\n", ldg->progname, db_strerror(ret)); 589 return (ret); 590 } 591 dbenv = *dbenvp; 592 dbenv->set_errfile(dbenv, stderr); 593 dbenv->set_errpfx(dbenv, ldg->progname); 594 if (ldg->passwd != NULL && (ret = dbenv->set_encrypt(dbenv, 595 ldg->passwd, DB_ENCRYPT_AES)) != 0) { 596 dbenv->err(dbenv, ret, "set_passwd"); 597 return (ret); 598 } 599 if ((ret = db_load_db_init(dbenv, ldg->home, ldg->cache, &ldg->private)) != 0) 600 return (ret); 601 dbenv->app_private = ldg; 602 603 return (0); 604} 605 606/* 607 * db_init -- 608 * Initialize the environment. 609 */ 610int 611db_load_db_init(dbenv, home, cache, is_private) 612 DB_ENV *dbenv; 613 char *home; 614 u_int32_t cache; 615 int *is_private; 616{ 617 u_int32_t flags; 618 int ret; 619 620 *is_private = 0; 621 /* We may be loading into a live environment. Try and join. */ 622 flags = DB_USE_ENVIRON | 623 DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN; 624 if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0) 625 return (0); 626 if (ret == DB_VERSION_MISMATCH) 627 goto err; 628 629 /* 630 * We're trying to load a database. 631 * 632 * An environment is required because we may be trying to look at 633 * databases in directories other than the current one. We could 634 * avoid using an environment iff the -h option wasn't specified, 635 * but that seems like more work than it's worth. 636 * 637 * No environment exists (or, at least no environment that includes 638 * an mpool region exists). Create one, but make it private so that 639 * no files are actually created. 640 */ 641 LF_CLR(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN); 642 LF_SET(DB_CREATE | DB_PRIVATE); 643 *is_private = 1; 644 if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) { 645 dbenv->err(dbenv, ret, "set_cachesize"); 646 return (1); 647 } 648 if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0) 649 return (0); 650 651 /* An environment is required. */ 652err: dbenv->err(dbenv, ret, "DB_ENV->open"); 653 return (1); 654} 655 656#define FLAG(name, value, keyword, flag) \ 657 if (strcmp(name, keyword) == 0) { \ 658 switch (*value) { \ 659 case '1': \ 660 if ((ret = dbp->set_flags(dbp, flag)) != 0) { \ 661 dbp->err(dbp, ret, "%s: set_flags: %s", \ 662 G(progname), name); \ 663 goto err; \ 664 } \ 665 break; \ 666 case '0': \ 667 break; \ 668 default: \ 669 db_load_badnum(dbenv); \ 670 goto err; \ 671 } \ 672 continue; \ 673 } 674#define NUMBER(name, value, keyword, func, t) \ 675 if (strcmp(name, keyword) == 0) { \ 676 if ((ret = __db_getlong(dbenv, \ 677 NULL, value, 0, LONG_MAX, &val)) != 0 || \ 678 (ret = dbp->func(dbp, (t)val)) != 0) \ 679 goto nameerr; \ 680 continue; \ 681 } 682#define STRING(name, value, keyword, func) \ 683 if (strcmp(name, keyword) == 0) { \ 684 if ((ret = dbp->func(dbp, value[0])) != 0) \ 685 goto nameerr; \ 686 continue; \ 687 } 688 689/* 690 * The code to check a command-line or input header argument against a list 691 * of configuration options. It's #defined because it's used in two places 692 * and the two places have gotten out of sync more than once. 693 */ 694#define CONFIGURATION_LIST_COMPARE \ 695 NUMBER(name, value, "bt_minkey", set_bt_minkey, u_int32_t); \ 696 FLAG(name, value, "chksum", DB_CHKSUM); \ 697 NUMBER(name, value, "db_lorder", set_lorder, int); \ 698 NUMBER(name, value, "db_pagesize", set_pagesize, u_int32_t); \ 699 FLAG(name, value, "duplicates", DB_DUP); \ 700 FLAG(name, value, "dupsort", DB_DUPSORT); \ 701 NUMBER(name, value, "extentsize", set_q_extentsize, u_int32_t); \ 702 NUMBER(name, value, "h_ffactor", set_h_ffactor, u_int32_t); \ 703 NUMBER(name, value, "h_nelem", set_h_nelem, u_int32_t); \ 704 NUMBER(name, value, "re_len", set_re_len, u_int32_t); \ 705 STRING(name, value, "re_pad", set_re_pad); \ 706 FLAG(name, value, "recnum", DB_RECNUM); \ 707 FLAG(name, value, "renumber", DB_RENUMBER) 708 709/* 710 * configure -- 711 * Handle command-line configuration options. 712 */ 713int 714db_load_configure(dbenv, dbp, clp, subdbp, keysp) 715 DB_ENV *dbenv; 716 DB *dbp; 717 char **clp, **subdbp; 718 int *keysp; 719{ 720 long val; 721 int ret, savech; 722 char *name, *value; 723 724 for (; (name = *clp) != NULL; *--value = savech, ++clp) { 725 if ((value = strchr(name, '=')) == NULL) { 726 dbp->errx(dbp, 727 "command-line configuration uses name=value format"); 728 return (1); 729 } 730 savech = *value; 731 *value++ = '\0'; 732 733 if (strcmp(name, "database") == 0 || 734 strcmp(name, "subdatabase") == 0) { 735 if (*subdbp != NULL) 736 free(*subdbp); 737 if ((*subdbp = strdup(value)) == NULL) { 738 dbp->err(dbp, ENOMEM, NULL); 739 return (1); 740 } 741 continue; 742 } 743 if (strcmp(name, "keys") == 0) { 744 if (strcmp(value, "1") == 0) 745 *keysp = 1; 746 else if (strcmp(value, "0") == 0) 747 *keysp = 0; 748 else { 749 db_load_badnum(dbenv); 750 return (1); 751 } 752 continue; 753 } 754 755 CONFIGURATION_LIST_COMPARE; 756 757 dbp->errx(dbp, 758 "unknown command-line configuration keyword \"%s\"", name); 759 return (1); 760 } 761 return (0); 762 763nameerr: 764 dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value); 765err: return (1); 766} 767 768/* 769 * rheader -- 770 * Read the header message. 771 */ 772int 773db_load_rheader(dbenv, dbp, dbtypep, subdbp, checkprintp, keysp) 774 DB_ENV *dbenv; 775 DB *dbp; 776 DBTYPE *dbtypep; 777 char **subdbp; 778 int *checkprintp, *keysp; 779{ 780 size_t buflen, linelen, start; 781 long val; 782 int ch, first, hdr, ret; 783 char *buf, *name, *p, *value; 784 785 *dbtypep = DB_UNKNOWN; 786 *checkprintp = 0; 787 name = NULL; 788 789 /* 790 * We start with a smallish buffer; most headers are small. 791 * We may need to realloc it for a large subdatabase name. 792 */ 793 buflen = 4096; 794 if (G(hdrbuf) == NULL) { 795 hdr = 0; 796 if ((buf = malloc(buflen)) == NULL) 797 goto memerr; 798 G(hdrbuf) = buf; 799 G(origline) = G(lineno); 800 } else { 801 hdr = 1; 802 buf = G(hdrbuf); 803 G(lineno) = G(origline); 804 } 805 806 start = 0; 807 for (first = 1;; first = 0) { 808 ++G(lineno); 809 810 /* Read a line, which may be of arbitrary length, into buf. */ 811 linelen = 0; 812 buf = &G(hdrbuf)[start]; 813 if (hdr == 0) { 814 for (;;) { 815 if ((ch = getchar()) == EOF) { 816 if (!first || ferror(stdin)) 817 goto badfmt; 818 G(endofile) = 1; 819 break; 820 } 821 822 /* 823 * If the buffer is too small, double it. 824 */ 825 if (linelen + start == buflen) { 826 G(hdrbuf) = 827 realloc(G(hdrbuf), buflen *= 2); 828 if (G(hdrbuf) == NULL) 829 goto memerr; 830 buf = &G(hdrbuf)[start]; 831 } 832 833 if (ch == '\n') 834 break; 835 836 buf[linelen++] = ch; 837 } 838 if (G(endofile) == 1) 839 break; 840 buf[linelen++] = '\0'; 841 } else 842 linelen = strlen(buf) + 1; 843 start += linelen; 844 845 if (name != NULL) { 846 free(name); 847 name = NULL; 848 } 849 /* If we don't see the expected information, it's an error. */ 850 if ((name = strdup(buf)) == NULL) 851 goto memerr; 852 if ((p = strchr(name, '=')) == NULL) 853 goto badfmt; 854 *p++ = '\0'; 855 856 value = p--; 857 858 if (name[0] == '\0') 859 goto badfmt; 860 861 /* 862 * The only values that may be zero-length are database names. 863 * In the original Berkeley DB code it was possible to create 864 * zero-length database names, and the db_load code was then 865 * changed to allow such databases to be be dumped and loaded. 866 * [#8204] 867 */ 868 if (strcmp(name, "database") == 0 || 869 strcmp(name, "subdatabase") == 0) { 870 if ((ret = db_load_convprintable(dbenv, value, subdbp)) != 0) { 871 dbp->err(dbp, ret, "error reading db name"); 872 goto err; 873 } 874 continue; 875 } 876 877 /* No other values may be zero-length. */ 878 if (value[0] == '\0') 879 goto badfmt; 880 881 if (strcmp(name, "HEADER") == 0) 882 break; 883 if (strcmp(name, "VERSION") == 0) { 884 /* 885 * Version 1 didn't have a "VERSION" header line. We 886 * only support versions 1, 2, and 3 of the dump format. 887 */ 888 G(version) = atoi(value); 889 890 if (G(version) > 3) { 891 dbp->errx(dbp, 892 "line %lu: VERSION %d is unsupported", 893 G(lineno), G(version)); 894 goto err; 895 } 896 continue; 897 } 898 if (strcmp(name, "format") == 0) { 899 if (strcmp(value, "bytevalue") == 0) { 900 *checkprintp = 0; 901 continue; 902 } 903 if (strcmp(value, "print") == 0) { 904 *checkprintp = 1; 905 continue; 906 } 907 goto badfmt; 908 } 909 if (strcmp(name, "type") == 0) { 910 if (strcmp(value, "btree") == 0) { 911 *dbtypep = DB_BTREE; 912 continue; 913 } 914 if (strcmp(value, "hash") == 0) { 915 *dbtypep = DB_HASH; 916 continue; 917 } 918 if (strcmp(value, "recno") == 0) { 919 *dbtypep = DB_RECNO; 920 continue; 921 } 922 if (strcmp(value, "queue") == 0) { 923 *dbtypep = DB_QUEUE; 924 continue; 925 } 926 dbp->errx(dbp, "line %lu: unknown type", G(lineno)); 927 goto err; 928 } 929 if (strcmp(name, "keys") == 0) { 930 if (strcmp(value, "1") == 0) 931 *keysp = 1; 932 else if (strcmp(value, "0") == 0) 933 *keysp = 0; 934 else { 935 db_load_badnum(dbenv); 936 goto err; 937 } 938 continue; 939 } 940 941 CONFIGURATION_LIST_COMPARE; 942 943 dbp->errx(dbp, 944 "unknown input-file header configuration keyword \"%s\"", 945 name); 946 goto err; 947 } 948 ret = 0; 949 950 if (0) { 951nameerr: dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value); 952 ret = 1; 953 } 954 if (0) { 955badfmt: dbp->errx(dbp, "line %lu: unexpected format", G(lineno)); 956 ret = 1; 957 } 958 if (0) { 959memerr: dbp->errx(dbp, "unable to allocate memory"); 960err: ret = 1; 961 } 962 if (name != NULL) 963 free(name); 964 return (ret); 965} 966 967/* 968 * Macro to convert a pair of hex bytes to a decimal value. 969 * 970 * !!! 971 * Note that this macro is side-effect safe. This was done deliberately, 972 * callers depend on it. 973 */ 974#define DIGITIZE(store, v1, v2) { \ 975 char _v1, _v2; \ 976 _v1 = (v1); \ 977 _v2 = (v2); \ 978 if ((_v1) > 'f' || (_v2) > 'f') \ 979 return (db_load_badend(dbenv)); \ 980 (store) = \ 981 ((_v1) == '0' ? 0 : \ 982 ((_v1) == '1' ? 1 : \ 983 ((_v1) == '2' ? 2 : \ 984 ((_v1) == '3' ? 3 : \ 985 ((_v1) == '4' ? 4 : \ 986 ((_v1) == '5' ? 5 : \ 987 ((_v1) == '6' ? 6 : \ 988 ((_v1) == '7' ? 7 : \ 989 ((_v1) == '8' ? 8 : \ 990 ((_v1) == '9' ? 9 : \ 991 ((_v1) == 'a' ? 10 : \ 992 ((_v1) == 'b' ? 11 : \ 993 ((_v1) == 'c' ? 12 : \ 994 ((_v1) == 'd' ? 13 : \ 995 ((_v1) == 'e' ? 14 : 15))))))))))))))) << 4 | \ 996 ((_v2) == '0' ? 0 : \ 997 ((_v2) == '1' ? 1 : \ 998 ((_v2) == '2' ? 2 : \ 999 ((_v2) == '3' ? 3 : \ 1000 ((_v2) == '4' ? 4 : \ 1001 ((_v2) == '5' ? 5 : \ 1002 ((_v2) == '6' ? 6 : \ 1003 ((_v2) == '7' ? 7 : \ 1004 ((_v2) == '8' ? 8 : \ 1005 ((_v2) == '9' ? 9 : \ 1006 ((_v2) == 'a' ? 10 : \ 1007 ((_v2) == 'b' ? 11 : \ 1008 ((_v2) == 'c' ? 12 : \ 1009 ((_v2) == 'd' ? 13 : \ 1010 ((_v2) == 'e' ? 14 : 15))))))))))))))); \ 1011} 1012 1013/* 1014 * convprintable -- 1015 * Convert a printable-encoded string into a newly allocated string. 1016 * 1017 * In an ideal world, this would probably share code with dbt_rprint, but 1018 * that's set up to read character-by-character (to avoid large memory 1019 * allocations that aren't likely to be a problem here), and this has fewer 1020 * special cases to deal with. 1021 * 1022 * Note that despite the printable encoding, the char * interface to this 1023 * function (which is, not coincidentally, also used for database naming) 1024 * means that outstr cannot contain any nuls. 1025 */ 1026int 1027db_load_convprintable(dbenv, instr, outstrp) 1028 DB_ENV *dbenv; 1029 char *instr, **outstrp; 1030{ 1031 char *outstr; 1032 1033 /* 1034 * Just malloc a string big enough for the whole input string; 1035 * the output string will be smaller (or of equal length). 1036 * 1037 * Note that we may be passed a zero-length string and need to 1038 * be able to duplicate it. 1039 */ 1040 if ((outstr = malloc(strlen(instr) + 1)) == NULL) 1041 return (ENOMEM); 1042 1043 *outstrp = outstr; 1044 1045 for ( ; *instr != '\0'; instr++) 1046 if (*instr == '\\') { 1047 if (*++instr == '\\') { 1048 *outstr++ = '\\'; 1049 continue; 1050 } 1051 DIGITIZE(*outstr++, *instr, *++instr); 1052 } else 1053 *outstr++ = *instr; 1054 1055 *outstr = '\0'; 1056 1057 return (0); 1058} 1059 1060/* 1061 * dbt_rprint -- 1062 * Read a printable line into a DBT structure. 1063 */ 1064int 1065db_load_dbt_rprint(dbenv, dbtp) 1066 DB_ENV *dbenv; 1067 DBT *dbtp; 1068{ 1069 u_int32_t len; 1070 u_int8_t *p; 1071 int c1, c2, escape, first; 1072 char buf[32]; 1073 1074 ++G(lineno); 1075 1076 first = 1; 1077 escape = 0; 1078 for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { 1079 if (c1 == EOF) { 1080 if (len == 0) { 1081 G(endofile) = G(endodata) = 1; 1082 return (0); 1083 } 1084 return (db_load_badend(dbenv)); 1085 } 1086 if (first) { 1087 first = 0; 1088 if (G(version) > 1) { 1089 if (c1 != ' ') { 1090 buf[0] = c1; 1091 if (fgets(buf + 1, 1092 sizeof(buf) - 1, stdin) == NULL || 1093 strcmp(buf, "DATA=END\n") != 0) 1094 return (db_load_badend(dbenv)); 1095 G(endodata) = 1; 1096 return (0); 1097 } 1098 continue; 1099 } 1100 } 1101 if (escape) { 1102 if (c1 != '\\') { 1103 if ((c2 = getchar()) == EOF) 1104 return (db_load_badend(dbenv)); 1105 DIGITIZE(c1, c1, c2); 1106 } 1107 escape = 0; 1108 } else 1109 if (c1 == '\\') { 1110 escape = 1; 1111 continue; 1112 } 1113 if (len >= dbtp->ulen - 10) { 1114 dbtp->ulen *= 2; 1115 if ((dbtp->data = 1116 realloc(dbtp->data, dbtp->ulen)) == NULL) { 1117 dbenv->err(dbenv, ENOMEM, NULL); 1118 return (1); 1119 } 1120 p = (u_int8_t *)dbtp->data + len; 1121 } 1122 ++len; 1123 *p++ = c1; 1124 } 1125 dbtp->size = len; 1126 1127 return (0); 1128} 1129 1130/* 1131 * dbt_rdump -- 1132 * Read a byte dump line into a DBT structure. 1133 */ 1134int 1135db_load_dbt_rdump(dbenv, dbtp) 1136 DB_ENV *dbenv; 1137 DBT *dbtp; 1138{ 1139 u_int32_t len; 1140 u_int8_t *p; 1141 int c1, c2, first; 1142 char buf[32]; 1143 1144 ++G(lineno); 1145 1146 first = 1; 1147 for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { 1148 if (c1 == EOF) { 1149 if (len == 0) { 1150 G(endofile) = G(endodata) = 1; 1151 return (0); 1152 } 1153 return (db_load_badend(dbenv)); 1154 } 1155 if (first) { 1156 first = 0; 1157 if (G(version) > 1) { 1158 if (c1 != ' ') { 1159 buf[0] = c1; 1160 if (fgets(buf + 1, 1161 sizeof(buf) - 1, stdin) == NULL || 1162 strcmp(buf, "DATA=END\n") != 0) 1163 return (db_load_badend(dbenv)); 1164 G(endodata) = 1; 1165 return (0); 1166 } 1167 continue; 1168 } 1169 } 1170 if ((c2 = getchar()) == EOF) 1171 return (db_load_badend(dbenv)); 1172 if (len >= dbtp->ulen - 10) { 1173 dbtp->ulen *= 2; 1174 if ((dbtp->data = 1175 realloc(dbtp->data, dbtp->ulen)) == NULL) { 1176 dbenv->err(dbenv, ENOMEM, NULL); 1177 return (1); 1178 } 1179 p = (u_int8_t *)dbtp->data + len; 1180 } 1181 ++len; 1182 DIGITIZE(*p++, c1, c2); 1183 } 1184 dbtp->size = len; 1185 1186 return (0); 1187} 1188 1189/* 1190 * dbt_rrecno -- 1191 * Read a record number dump line into a DBT structure. 1192 */ 1193int 1194db_load_dbt_rrecno(dbenv, dbtp, ishex) 1195 DB_ENV *dbenv; 1196 DBT *dbtp; 1197 int ishex; 1198{ 1199 char buf[32], *p, *q; 1200 u_long recno; 1201 1202 ++G(lineno); 1203 1204 if (fgets(buf, sizeof(buf), stdin) == NULL) { 1205 G(endofile) = G(endodata) = 1; 1206 return (0); 1207 } 1208 1209 if (strcmp(buf, "DATA=END\n") == 0) { 1210 G(endodata) = 1; 1211 return (0); 1212 } 1213 1214 if (buf[0] != ' ') 1215 goto err; 1216 1217 /* 1218 * If we're expecting a hex key, do an in-place conversion 1219 * of hex to straight ASCII before calling __db_getulong(). 1220 */ 1221 if (ishex) { 1222 for (p = q = buf + 1; *q != '\0' && *q != '\n';) { 1223 /* 1224 * 0-9 in hex are 0x30-0x39, so this is easy. 1225 * We should alternate between 3's and [0-9], and 1226 * if the [0-9] are something unexpected, 1227 * __db_getulong will fail, so we only need to catch 1228 * end-of-string conditions. 1229 */ 1230 if (*q++ != '3') 1231 goto err; 1232 if (*q == '\n' || *q == '\0') 1233 goto err; 1234 *p++ = *q++; 1235 } 1236 *p = '\0'; 1237 } 1238 1239 if (__db_getulong(dbenv, G(progname), buf + 1, 0, 0, &recno)) 1240 goto err; 1241 1242 *((db_recno_t *)dbtp->data) = recno; 1243 dbtp->size = sizeof(db_recno_t); 1244 return (0); 1245 1246err: return (db_load_badend(dbenv)); 1247} 1248 1249int 1250db_load_dbt_to_recno(dbenv, dbt, recnop) 1251 DB_ENV *dbenv; 1252 DBT *dbt; 1253 db_recno_t *recnop; 1254{ 1255 char buf[32]; /* Large enough for 2^64. */ 1256 1257 memcpy(buf, dbt->data, dbt->size); 1258 buf[dbt->size] = '\0'; 1259 1260 return (__db_getulong(dbenv, G(progname), buf, 0, 0, (u_long *)recnop)); 1261} 1262 1263/* 1264 * badnum -- 1265 * Display the bad number message. 1266 */ 1267void 1268db_load_badnum(dbenv) 1269 DB_ENV *dbenv; 1270{ 1271 dbenv->errx(dbenv, 1272 "boolean name=value pairs require a value of 0 or 1"); 1273} 1274 1275/* 1276 * badend -- 1277 * Display the bad end to input message. 1278 */ 1279int 1280db_load_badend(dbenv) 1281 DB_ENV *dbenv; 1282{ 1283 dbenv->errx(dbenv, "unexpected end of input data or key/data pair"); 1284 return (1); 1285} 1286 1287/* 1288 * usage -- 1289 * Display the usage message. 1290 */ 1291int 1292db_load_usage() 1293{ 1294 (void)fprintf(stderr, "usage: %s %s\n\t%s\n", progname, 1295 "[-nTV] [-c name=value] [-f file]", 1296 "[-h home] [-P password] [-t btree | hash | recno | queue] db_file"); 1297 (void)fprintf(stderr, "usage: %s %s\n", 1298 progname, "-r lsn | fileid [-h home] [-P password] db_file"); 1299 return (EXIT_FAILURE); 1300} 1301 1302int 1303db_load_version_check() 1304{ 1305 int v_major, v_minor, v_patch; 1306 1307 /* Make sure we're loaded with the right version of the DB library. */ 1308 (void)db_version(&v_major, &v_minor, &v_patch); 1309 if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) { 1310 fprintf(stderr, 1311 "%s: version %d.%d doesn't match library version %d.%d\n", 1312 progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, 1313 v_major, v_minor); 1314 return (EXIT_FAILURE); 1315 } 1316 return (0); 1317} 1318