1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Mike Olson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <fcntl.h> 37 #include <db.h> 38 #include <errno.h> 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include "btree.h" 44 45 typedef struct cmd_table { 46 char *cmd; 47 int nargs; 48 int rconv; 49 void (*func)(DB *, char **); 50 char *usage, *descrip; 51 } cmd_table; 52 53 int stopstop; 54 DB *globaldb; 55 56 void append(DB *, char **); 57 void bstat(DB *, char **); 58 void cursor(DB *, char **); 59 void delcur(DB *, char **); 60 void delete(DB *, char **); 61 void dump(DB *, char **); 62 void first(DB *, char **); 63 void get(DB *, char **); 64 void help(DB *, char **); 65 void iafter(DB *, char **); 66 void ibefore(DB *, char **); 67 void icursor(DB *, char **); 68 void insert(DB *, char **); 69 void keydata(DBT *, DBT *); 70 void last(DB *, char **); 71 void list(DB *, char **); 72 void load(DB *, char **); 73 void mstat(DB *, char **); 74 void next(DB *, char **); 75 int parse(char *, char **, int); 76 void previous(DB *, char **); 77 void show(DB *, char **); 78 void usage(void); 79 void user(DB *); 80 81 cmd_table commands[] = { 82 "?", 0, 0, help, "help", NULL, 83 "a", 2, 1, append, "append key def", "append key with data def", 84 "b", 0, 0, bstat, "bstat", "stat btree", 85 "c", 1, 1, cursor, "cursor word", "move cursor to word", 86 "delc", 0, 0, delcur, "delcur", "delete key the cursor references", 87 "dele", 1, 1, delete, "delete word", "delete word", 88 "d", 0, 0, dump, "dump", "dump database", 89 "f", 0, 0, first, "first", "move cursor to first record", 90 "g", 1, 1, get, "get key", "locate key", 91 "h", 0, 0, help, "help", "print command summary", 92 "ia", 2, 1, iafter, "iafter key data", "insert data after key", 93 "ib", 2, 1, ibefore, "ibefore key data", "insert data before key", 94 "ic", 2, 1, icursor, "icursor key data", "replace cursor", 95 "in", 2, 1, insert, "insert key def", "insert key with data def", 96 "la", 0, 0, last, "last", "move cursor to last record", 97 "li", 1, 1, list, "list file", "list to a file", 98 "loa", 1, 0, load, "load file", NULL, 99 "loc", 1, 1, get, "get key", NULL, 100 "m", 0, 0, mstat, "mstat", "stat memory pool", 101 "n", 0, 0, next, "next", "move cursor forward one record", 102 "p", 0, 0, previous, "previous", "move cursor back one record", 103 "q", 0, 0, NULL, "quit", "quit", 104 "sh", 1, 0, show, "show page", "dump a page", 105 { NULL }, 106 }; 107 108 int recno; /* use record numbers */ 109 char *dict = "words"; /* default dictionary */ 110 char *progname; 111 112 int 113 main(argc, argv) 114 int argc; 115 char **argv; 116 { 117 int c; 118 DB *db; 119 BTREEINFO b; 120 121 progname = *argv; 122 123 b.flags = 0; 124 b.cachesize = 0; 125 b.maxkeypage = 0; 126 b.minkeypage = 0; 127 b.psize = 0; 128 b.compare = NULL; 129 b.prefix = NULL; 130 b.lorder = 0; 131 132 while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) { 133 switch (c) { 134 case 'b': 135 b.lorder = BIG_ENDIAN; 136 break; 137 case 'c': 138 b.cachesize = atoi(optarg); 139 break; 140 case 'd': 141 b.flags |= R_DUP; 142 break; 143 case 'i': 144 dict = optarg; 145 break; 146 case 'l': 147 b.lorder = LITTLE_ENDIAN; 148 break; 149 case 'p': 150 b.psize = atoi(optarg); 151 break; 152 case 'r': 153 recno = 1; 154 break; 155 case 'u': 156 b.flags = 0; 157 break; 158 default: 159 usage(); 160 } 161 } 162 argc -= optind; 163 argv += optind; 164 165 if (recno) 166 db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR, 167 0, DB_RECNO, NULL); 168 else 169 db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR, 170 0600, DB_BTREE, &b); 171 172 if (db == NULL) { 173 (void)fprintf(stderr, "dbopen: %s\n", strerror(errno)); 174 exit(1); 175 } 176 globaldb = db; 177 user(db); 178 exit(0); 179 /* NOTREACHED */ 180 } 181 182 void 183 user(db) 184 DB *db; 185 { 186 FILE *ifp; 187 int argc, i, last; 188 char *lbuf, *argv[4], buf[512]; 189 190 if ((ifp = fopen("/dev/tty", "r")) == NULL) { 191 (void)fprintf(stderr, 192 "/dev/tty: %s\n", strerror(errno)); 193 exit(1); 194 } 195 for (last = 0;;) { 196 (void)printf("> "); 197 (void)fflush(stdout); 198 if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL) 199 break; 200 if (lbuf[0] == '\n') { 201 i = last; 202 goto uselast; 203 } 204 lbuf[strlen(lbuf) - 1] = '\0'; 205 206 if (lbuf[0] == 'q') 207 break; 208 209 argc = parse(lbuf, &argv[0], 3); 210 if (argc == 0) 211 continue; 212 213 for (i = 0; commands[i].cmd != NULL; i++) 214 if (strncmp(commands[i].cmd, argv[0], 215 strlen(commands[i].cmd)) == 0) 216 break; 217 218 if (commands[i].cmd == NULL) { 219 (void)fprintf(stderr, 220 "%s: command unknown ('help' for help)\n", lbuf); 221 continue; 222 } 223 224 if (commands[i].nargs != argc - 1) { 225 (void)fprintf(stderr, "usage: %s\n", commands[i].usage); 226 continue; 227 } 228 229 if (recno && commands[i].rconv) { 230 static recno_t nlong; 231 nlong = atoi(argv[1]); 232 argv[1] = (char *)&nlong; 233 } 234 uselast: last = i; 235 (*commands[i].func)(db, argv); 236 } 237 if ((db->sync)(db) == RET_ERROR) 238 perror("dbsync"); 239 else if ((db->close)(db) == RET_ERROR) 240 perror("dbclose"); 241 } 242 243 int 244 parse(lbuf, argv, maxargc) 245 char *lbuf, **argv; 246 int maxargc; 247 { 248 int argc = 0; 249 char *c; 250 251 c = lbuf; 252 while (isspace(*c)) 253 c++; 254 while (*c != '\0' && argc < maxargc) { 255 *argv++ = c; 256 argc++; 257 while (!isspace(*c) && *c != '\0') { 258 c++; 259 } 260 while (isspace(*c)) 261 *c++ = '\0'; 262 } 263 return (argc); 264 } 265 266 void 267 append(db, argv) 268 DB *db; 269 char **argv; 270 { 271 DBT key, data; 272 int status; 273 274 if (!recno) { 275 (void)fprintf(stderr, 276 "append only available for recno db's.\n"); 277 return; 278 } 279 key.data = argv[1]; 280 key.size = sizeof(recno_t); 281 data.data = argv[2]; 282 data.size = strlen(data.data); 283 status = (db->put)(db, &key, &data, R_APPEND); 284 switch (status) { 285 case RET_ERROR: 286 perror("append/put"); 287 break; 288 case RET_SPECIAL: 289 (void)printf("%s (duplicate key)\n", argv[1]); 290 break; 291 case RET_SUCCESS: 292 break; 293 } 294 } 295 296 void 297 cursor(db, argv) 298 DB *db; 299 char **argv; 300 { 301 DBT data, key; 302 int status; 303 304 key.data = argv[1]; 305 if (recno) 306 key.size = sizeof(recno_t); 307 else 308 key.size = strlen(argv[1]) + 1; 309 status = (*db->seq)(db, &key, &data, R_CURSOR); 310 switch (status) { 311 case RET_ERROR: 312 perror("cursor/seq"); 313 break; 314 case RET_SPECIAL: 315 (void)printf("key not found\n"); 316 break; 317 case RET_SUCCESS: 318 keydata(&key, &data); 319 break; 320 } 321 } 322 323 void 324 delcur(db, argv) 325 DB *db; 326 char **argv; 327 { 328 int status; 329 330 status = (*db->del)(db, NULL, R_CURSOR); 331 332 if (status == RET_ERROR) 333 perror("delcur/del"); 334 } 335 336 void 337 delete(db, argv) 338 DB *db; 339 char **argv; 340 { 341 DBT key; 342 int status; 343 344 key.data = argv[1]; 345 if (recno) 346 key.size = sizeof(recno_t); 347 else 348 key.size = strlen(argv[1]) + 1; 349 350 status = (*db->del)(db, &key, 0); 351 switch (status) { 352 case RET_ERROR: 353 perror("delete/del"); 354 break; 355 case RET_SPECIAL: 356 (void)printf("key not found\n"); 357 break; 358 case RET_SUCCESS: 359 break; 360 } 361 } 362 363 void 364 dump(db, argv) 365 DB *db; 366 char **argv; 367 { 368 __bt_dump(db); 369 } 370 371 void 372 first(db, argv) 373 DB *db; 374 char **argv; 375 { 376 DBT data, key; 377 int status; 378 379 status = (*db->seq)(db, &key, &data, R_FIRST); 380 381 switch (status) { 382 case RET_ERROR: 383 perror("first/seq"); 384 break; 385 case RET_SPECIAL: 386 (void)printf("no more keys\n"); 387 break; 388 case RET_SUCCESS: 389 keydata(&key, &data); 390 break; 391 } 392 } 393 394 void 395 get(db, argv) 396 DB *db; 397 char **argv; 398 { 399 DBT data, key; 400 int status; 401 402 key.data = argv[1]; 403 if (recno) 404 key.size = sizeof(recno_t); 405 else 406 key.size = strlen(argv[1]) + 1; 407 408 status = (*db->get)(db, &key, &data, 0); 409 410 switch (status) { 411 case RET_ERROR: 412 perror("get/get"); 413 break; 414 case RET_SPECIAL: 415 (void)printf("key not found\n"); 416 break; 417 case RET_SUCCESS: 418 keydata(&key, &data); 419 break; 420 } 421 } 422 423 void 424 help(db, argv) 425 DB *db; 426 char **argv; 427 { 428 int i; 429 430 for (i = 0; commands[i].cmd; i++) 431 if (commands[i].descrip) 432 (void)printf("%s: %s\n", 433 commands[i].usage, commands[i].descrip); 434 } 435 436 void 437 iafter(db, argv) 438 DB *db; 439 char **argv; 440 { 441 DBT key, data; 442 int status; 443 444 if (!recno) { 445 (void)fprintf(stderr, 446 "iafter only available for recno db's.\n"); 447 return; 448 } 449 key.data = argv[1]; 450 key.size = sizeof(recno_t); 451 data.data = argv[2]; 452 data.size = strlen(data.data); 453 status = (db->put)(db, &key, &data, R_IAFTER); 454 switch (status) { 455 case RET_ERROR: 456 perror("iafter/put"); 457 break; 458 case RET_SPECIAL: 459 (void)printf("%s (duplicate key)\n", argv[1]); 460 break; 461 case RET_SUCCESS: 462 break; 463 } 464 } 465 466 void 467 ibefore(db, argv) 468 DB *db; 469 char **argv; 470 { 471 DBT key, data; 472 int status; 473 474 if (!recno) { 475 (void)fprintf(stderr, 476 "ibefore only available for recno db's.\n"); 477 return; 478 } 479 key.data = argv[1]; 480 key.size = sizeof(recno_t); 481 data.data = argv[2]; 482 data.size = strlen(data.data); 483 status = (db->put)(db, &key, &data, R_IBEFORE); 484 switch (status) { 485 case RET_ERROR: 486 perror("ibefore/put"); 487 break; 488 case RET_SPECIAL: 489 (void)printf("%s (duplicate key)\n", argv[1]); 490 break; 491 case RET_SUCCESS: 492 break; 493 } 494 } 495 496 void 497 icursor(db, argv) 498 DB *db; 499 char **argv; 500 { 501 int status; 502 DBT data, key; 503 504 key.data = argv[1]; 505 if (recno) 506 key.size = sizeof(recno_t); 507 else 508 key.size = strlen(argv[1]) + 1; 509 data.data = argv[2]; 510 data.size = strlen(argv[2]) + 1; 511 512 status = (*db->put)(db, &key, &data, R_CURSOR); 513 switch (status) { 514 case RET_ERROR: 515 perror("icursor/put"); 516 break; 517 case RET_SPECIAL: 518 (void)printf("%s (duplicate key)\n", argv[1]); 519 break; 520 case RET_SUCCESS: 521 break; 522 } 523 } 524 525 void 526 insert(db, argv) 527 DB *db; 528 char **argv; 529 { 530 int status; 531 DBT data, key; 532 533 key.data = argv[1]; 534 if (recno) 535 key.size = sizeof(recno_t); 536 else 537 key.size = strlen(argv[1]) + 1; 538 data.data = argv[2]; 539 data.size = strlen(argv[2]) + 1; 540 541 status = (*db->put)(db, &key, &data, R_NOOVERWRITE); 542 switch (status) { 543 case RET_ERROR: 544 perror("insert/put"); 545 break; 546 case RET_SPECIAL: 547 (void)printf("%s (duplicate key)\n", argv[1]); 548 break; 549 case RET_SUCCESS: 550 break; 551 } 552 } 553 554 void 555 last(db, argv) 556 DB *db; 557 char **argv; 558 { 559 DBT data, key; 560 int status; 561 562 status = (*db->seq)(db, &key, &data, R_LAST); 563 564 switch (status) { 565 case RET_ERROR: 566 perror("last/seq"); 567 break; 568 case RET_SPECIAL: 569 (void)printf("no more keys\n"); 570 break; 571 case RET_SUCCESS: 572 keydata(&key, &data); 573 break; 574 } 575 } 576 577 void 578 list(db, argv) 579 DB *db; 580 char **argv; 581 { 582 DBT data, key; 583 FILE *fp; 584 int status; 585 586 if ((fp = fopen(argv[1], "w")) == NULL) { 587 (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 588 return; 589 } 590 status = (*db->seq)(db, &key, &data, R_FIRST); 591 while (status == RET_SUCCESS) { 592 (void)fprintf(fp, "%s\n", key.data); 593 status = (*db->seq)(db, &key, &data, R_NEXT); 594 } 595 if (status == RET_ERROR) 596 perror("list/seq"); 597 } 598 599 DB *BUGdb; 600 void 601 load(db, argv) 602 DB *db; 603 char **argv; 604 { 605 char *p, *t; 606 FILE *fp; 607 DBT data, key; 608 recno_t cnt; 609 size_t len; 610 int status; 611 char *lp, buf[16 * 1024]; 612 613 BUGdb = db; 614 if ((fp = fopen(argv[1], "r")) == NULL) { 615 (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 616 return; 617 } 618 (void)printf("loading %s...\n", argv[1]); 619 620 for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) { 621 if (recno) { 622 key.data = &cnt; 623 key.size = sizeof(recno_t); 624 data.data = lp; 625 data.size = len + 1; 626 } else { 627 key.data = lp; 628 key.size = len + 1; 629 for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--); 630 *t = '\0'; 631 data.data = buf; 632 data.size = len + 1; 633 } 634 635 status = (*db->put)(db, &key, &data, R_NOOVERWRITE); 636 switch (status) { 637 case RET_ERROR: 638 perror("load/put"); 639 exit(1); 640 case RET_SPECIAL: 641 if (recno) 642 (void)fprintf(stderr, 643 "duplicate: %ld {%s}\n", cnt, data.data); 644 else 645 (void)fprintf(stderr, 646 "duplicate: %ld {%s}\n", cnt, key.data); 647 exit(1); 648 case RET_SUCCESS: 649 break; 650 } 651 } 652 (void)fclose(fp); 653 } 654 655 void 656 next(db, argv) 657 DB *db; 658 char **argv; 659 { 660 DBT data, key; 661 int status; 662 663 status = (*db->seq)(db, &key, &data, R_NEXT); 664 665 switch (status) { 666 case RET_ERROR: 667 perror("next/seq"); 668 break; 669 case RET_SPECIAL: 670 (void)printf("no more keys\n"); 671 break; 672 case RET_SUCCESS: 673 keydata(&key, &data); 674 break; 675 } 676 } 677 678 void 679 previous(db, argv) 680 DB *db; 681 char **argv; 682 { 683 DBT data, key; 684 int status; 685 686 status = (*db->seq)(db, &key, &data, R_PREV); 687 688 switch (status) { 689 case RET_ERROR: 690 perror("previous/seq"); 691 break; 692 case RET_SPECIAL: 693 (void)printf("no more keys\n"); 694 break; 695 case RET_SUCCESS: 696 keydata(&key, &data); 697 break; 698 } 699 } 700 701 void 702 show(db, argv) 703 DB *db; 704 char **argv; 705 { 706 BTREE *t; 707 PAGE *h; 708 pgno_t pg; 709 710 pg = atoi(argv[1]); 711 t = db->internal; 712 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) { 713 (void)printf("getpage of %ld failed\n", pg); 714 return; 715 } 716 if (pg == 0) 717 __bt_dmpage(h); 718 else 719 __bt_dpage(h); 720 mpool_put(t->bt_mp, h, 0); 721 } 722 723 void 724 bstat(db, argv) 725 DB *db; 726 char **argv; 727 { 728 (void)printf("BTREE\n"); 729 __bt_stat(db); 730 } 731 732 void 733 mstat(db, argv) 734 DB *db; 735 char **argv; 736 { 737 (void)printf("MPOOL\n"); 738 mpool_stat(((BTREE *)db->internal)->bt_mp); 739 } 740 741 void 742 keydata(key, data) 743 DBT *key, *data; 744 { 745 if (!recno && key->size > 0) 746 (void)printf("%s/", key->data); 747 if (data->size > 0) 748 (void)printf("%s", data->data); 749 (void)printf("\n"); 750 } 751 752 void 753 usage() 754 { 755 (void)fprintf(stderr, 756 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n", 757 progname); 758 exit (1); 759 } 760