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