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