1 /* 2 Unix SMB/CIFS implementation. 3 Samba database functions 4 Copyright (C) Andrew Tridgell 1999-2000 5 Copyright (C) Paul `Rusty' Russell 2000 6 Copyright (C) Jeremy Allison 2000 7 Copyright (C) Andrew Esh 2001 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24 #include "config.h" 25 #include <errno.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <fcntl.h> 32 #include <time.h> 33 #include <sys/mman.h> 34 #include <sys/stat.h> 35 #include <sys/time.h> 36 #include <ctype.h> 37 #include <signal.h> 38 #include <stdarg.h> 39 40 #include "tdb.h" 41 42 static int do_command(void); 43 const char *cmdname; 44 char *arg1, *arg2; 45 size_t arg1len, arg2len; 46 int bIterate = 0; 47 char *line; 48 TDB_DATA iterate_kbuf; 49 char cmdline[1024]; 50 51 enum commands { 52 CMD_CREATE_TDB, 53 CMD_OPEN_TDB, 54 CMD_ERASE, 55 CMD_DUMP, 56 CMD_INSERT, 57 CMD_MOVE, 58 CMD_STORE, 59 CMD_SHOW, 60 CMD_KEYS, 61 CMD_HEXKEYS, 62 CMD_DELETE, 63 CMD_LIST_HASH_FREE, 64 CMD_LIST_FREE, 65 CMD_INFO, 66 CMD_FIRST, 67 CMD_NEXT, 68 CMD_SYSTEM, 69 CMD_QUIT, 70 CMD_HELP 71 }; 72 73 typedef struct { 74 const char *name; 75 enum commands cmd; 76 } COMMAND_TABLE; 77 78 COMMAND_TABLE cmd_table[] = { 79 {"create", CMD_CREATE_TDB}, 80 {"open", CMD_OPEN_TDB}, 81 {"erase", CMD_ERASE}, 82 {"dump", CMD_DUMP}, 83 {"insert", CMD_INSERT}, 84 {"move", CMD_MOVE}, 85 {"store", CMD_STORE}, 86 {"show", CMD_SHOW}, 87 {"keys", CMD_KEYS}, 88 {"hexkeys", CMD_HEXKEYS}, 89 {"delete", CMD_DELETE}, 90 {"list", CMD_LIST_HASH_FREE}, 91 {"free", CMD_LIST_FREE}, 92 {"info", CMD_INFO}, 93 {"first", CMD_FIRST}, 94 {"1", CMD_FIRST}, 95 {"next", CMD_NEXT}, 96 {"n", CMD_NEXT}, 97 {"quit", CMD_QUIT}, 98 {"q", CMD_QUIT}, 99 {"!", CMD_SYSTEM}, 100 {NULL, CMD_HELP} 101 }; 102 103 /* a tdb tool for manipulating a tdb database */ 104 105 static TDB_CONTEXT *tdb; 106 107 static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); 108 static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); 109 static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); 110 111 static void print_asc(const char *buf,int len) 112 { 113 int i; 114 115 /* We're probably printing ASCII strings so don't try to display 116 the trailing NULL character. */ 117 118 if (buf[len - 1] == 0) 119 len--; 120 121 for (i=0;i<len;i++) 122 printf("%c",isprint(buf[i])?buf[i]:'.'); 123 } 124 125 static void print_data(const char *buf,int len) 126 { 127 int i=0; 128 if (len<=0) return; 129 printf("[%03X] ",i); 130 for (i=0;i<len;) { 131 printf("%02X ",(int)buf[i]); 132 i++; 133 if (i%8 == 0) printf(" "); 134 if (i%16 == 0) { 135 print_asc(&buf[i-16],8); printf(" "); 136 print_asc(&buf[i-8],8); printf("\n"); 137 if (i<len) printf("[%03X] ",i); 138 } 139 } 140 if (i%16) { 141 int n; 142 143 n = 16 - (i%16); 144 printf(" "); 145 if (n>8) printf(" "); 146 while (n--) printf(" "); 147 148 n = i%16; 149 if (n > 8) n = 8; 150 print_asc(&buf[i-(i%16)],n); printf(" "); 151 n = (i%16) - n; 152 if (n>0) print_asc(&buf[i-n],n); 153 printf("\n"); 154 } 155 } 156 157 static void help(void) 158 { 159 printf("\n" 160 "tdbtool: \n" 161 " create dbname : create a database\n" 162 " open dbname : open an existing database\n" 163 " erase : erase the database\n" 164 " dump : dump the database as strings\n" 165 " keys : dump the database keys as strings\n" 166 " hexkeys : dump the database keys as hex values\n" 167 " info : print summary info about the database\n" 168 " insert key data : insert a record\n" 169 " move key file : move a record to a destination tdb\n" 170 " store key data : store a record (replace)\n" 171 " show key : show a record by key\n" 172 " delete key : delete a record by key\n" 173 " list : print the database hash table and freelist\n" 174 " free : print the database freelist\n" 175 " ! command : execute system command\n" 176 " 1 | first : print the first record\n" 177 " n | next : print the next record\n" 178 " q | quit : terminate\n" 179 " \\n : repeat 'next' command\n" 180 "\n"); 181 } 182 183 static void terror(const char *why) 184 { 185 printf("%s\n", why); 186 } 187 188 static void create_tdb(const char *tdbname) 189 { 190 if (tdb) tdb_close(tdb); 191 tdb = tdb_open(tdbname, 0, TDB_CLEAR_IF_FIRST, 192 O_RDWR | O_CREAT | O_TRUNC, 0600); 193 if (!tdb) { 194 printf("Could not create %s: %s\n", tdbname, strerror(errno)); 195 } 196 } 197 198 static void open_tdb(const char *tdbname) 199 { 200 if (tdb) tdb_close(tdb); 201 tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600); 202 if (!tdb) { 203 printf("Could not open %s: %s\n", tdbname, strerror(errno)); 204 } 205 } 206 207 static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen) 208 { 209 TDB_DATA key, dbuf; 210 211 if ((keyname == NULL) || (keylen == 0)) { 212 terror("need key"); 213 return; 214 } 215 216 key.dptr = (unsigned char *)keyname; 217 key.dsize = keylen; 218 dbuf.dptr = (unsigned char *)data; 219 dbuf.dsize = datalen; 220 221 if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) { 222 terror("insert failed"); 223 } 224 } 225 226 static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen) 227 { 228 TDB_DATA key, dbuf; 229 230 if ((keyname == NULL) || (keylen == 0)) { 231 terror("need key"); 232 return; 233 } 234 235 if ((data == NULL) || (datalen == 0)) { 236 terror("need data"); 237 return; 238 } 239 240 key.dptr = (unsigned char *)keyname; 241 key.dsize = keylen; 242 dbuf.dptr = (unsigned char *)data; 243 dbuf.dsize = datalen; 244 245 printf("Storing key:\n"); 246 print_rec(tdb, key, dbuf, NULL); 247 248 if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { 249 terror("store failed"); 250 } 251 } 252 253 static void show_tdb(char *keyname, size_t keylen) 254 { 255 TDB_DATA key, dbuf; 256 257 if ((keyname == NULL) || (keylen == 0)) { 258 terror("need key"); 259 return; 260 } 261 262 key.dptr = (unsigned char *)keyname; 263 key.dsize = keylen; 264 265 dbuf = tdb_fetch(tdb, key); 266 if (!dbuf.dptr) { 267 terror("fetch failed"); 268 return; 269 } 270 271 print_rec(tdb, key, dbuf, NULL); 272 273 free( dbuf.dptr ); 274 275 return; 276 } 277 278 static void delete_tdb(char *keyname, size_t keylen) 279 { 280 TDB_DATA key; 281 282 if ((keyname == NULL) || (keylen == 0)) { 283 terror("need key"); 284 return; 285 } 286 287 key.dptr = (unsigned char *)keyname; 288 key.dsize = keylen; 289 290 if (tdb_delete(tdb, key) != 0) { 291 terror("delete failed"); 292 } 293 } 294 295 static void move_rec(char *keyname, size_t keylen, char* tdbname) 296 { 297 TDB_DATA key, dbuf; 298 TDB_CONTEXT *dst_tdb; 299 300 if ((keyname == NULL) || (keylen == 0)) { 301 terror("need key"); 302 return; 303 } 304 305 if ( !tdbname ) { 306 terror("need destination tdb name"); 307 return; 308 } 309 310 key.dptr = (unsigned char *)keyname; 311 key.dsize = keylen; 312 313 dbuf = tdb_fetch(tdb, key); 314 if (!dbuf.dptr) { 315 terror("fetch failed"); 316 return; 317 } 318 319 print_rec(tdb, key, dbuf, NULL); 320 321 dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600); 322 if ( !dst_tdb ) { 323 terror("unable to open destination tdb"); 324 return; 325 } 326 327 if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) { 328 terror("failed to move record"); 329 } 330 else 331 printf("record moved\n"); 332 333 tdb_close( dst_tdb ); 334 335 return; 336 } 337 338 static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 339 { 340 printf("\nkey %d bytes\n", (int)key.dsize); 341 print_asc((const char *)key.dptr, key.dsize); 342 printf("\ndata %d bytes\n", (int)dbuf.dsize); 343 print_data((const char *)dbuf.dptr, dbuf.dsize); 344 return 0; 345 } 346 347 static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 348 { 349 printf("key %d bytes: ", (int)key.dsize); 350 print_asc((const char *)key.dptr, key.dsize); 351 printf("\n"); 352 return 0; 353 } 354 355 static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 356 { 357 printf("key %d bytes\n", (int)key.dsize); 358 print_data((const char *)key.dptr, key.dsize); 359 printf("\n"); 360 return 0; 361 } 362 363 static int total_bytes; 364 365 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 366 { 367 total_bytes += dbuf.dsize; 368 return 0; 369 } 370 371 static void info_tdb(void) 372 { 373 int count; 374 total_bytes = 0; 375 if ((count = tdb_traverse(tdb, traverse_fn, NULL)) == -1) 376 printf("Error = %s\n", tdb_errorstr(tdb)); 377 else 378 printf("%d records totalling %d bytes\n", count, total_bytes); 379 } 380 381 static char *tdb_getline(const char *prompt) 382 { 383 static char thisline[1024]; 384 char *p; 385 fputs(prompt, stdout); 386 thisline[0] = 0; 387 p = fgets(thisline, sizeof(thisline)-1, stdin); 388 if (p) p = strchr(p, '\n'); 389 if (p) *p = 0; 390 return p?thisline:NULL; 391 } 392 393 static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, 394 void *state) 395 { 396 return tdb_delete(the_tdb, key); 397 } 398 399 static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) 400 { 401 TDB_DATA dbuf; 402 *pkey = tdb_firstkey(the_tdb); 403 404 dbuf = tdb_fetch(the_tdb, *pkey); 405 if (!dbuf.dptr) terror("fetch failed"); 406 else { 407 print_rec(the_tdb, *pkey, dbuf, NULL); 408 } 409 } 410 411 static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) 412 { 413 TDB_DATA dbuf; 414 *pkey = tdb_nextkey(the_tdb, *pkey); 415 416 dbuf = tdb_fetch(the_tdb, *pkey); 417 if (!dbuf.dptr) 418 terror("fetch failed"); 419 else 420 print_rec(the_tdb, *pkey, dbuf, NULL); 421 } 422 423 static int do_command(void) 424 { 425 COMMAND_TABLE *ctp = cmd_table; 426 enum commands mycmd = CMD_HELP; 427 int cmd_len; 428 429 if (cmdname && strlen(cmdname) == 0) { 430 mycmd = CMD_NEXT; 431 } else { 432 while (ctp->name) { 433 cmd_len = strlen(ctp->name); 434 if (strncmp(ctp->name,cmdname,cmd_len) == 0) { 435 mycmd = ctp->cmd; 436 break; 437 } 438 ctp++; 439 } 440 } 441 442 switch (mycmd) { 443 case CMD_CREATE_TDB: 444 bIterate = 0; 445 create_tdb(arg1); 446 return 0; 447 case CMD_OPEN_TDB: 448 bIterate = 0; 449 open_tdb(arg1); 450 return 0; 451 case CMD_SYSTEM: 452 /* Shell command */ 453 system(arg1); 454 return 0; 455 case CMD_QUIT: 456 return 1; 457 default: 458 /* all the rest require a open database */ 459 if (!tdb) { 460 bIterate = 0; 461 terror("database not open"); 462 help(); 463 return 0; 464 } 465 switch (mycmd) { 466 case CMD_ERASE: 467 bIterate = 0; 468 tdb_traverse(tdb, do_delete_fn, NULL); 469 return 0; 470 case CMD_DUMP: 471 bIterate = 0; 472 tdb_traverse(tdb, print_rec, NULL); 473 return 0; 474 case CMD_INSERT: 475 bIterate = 0; 476 insert_tdb(arg1, arg1len,arg2,arg2len); 477 return 0; 478 case CMD_MOVE: 479 bIterate = 0; 480 move_rec(arg1,arg1len,arg2); 481 return 0; 482 case CMD_STORE: 483 bIterate = 0; 484 store_tdb(arg1,arg1len,arg2,arg2len); 485 return 0; 486 case CMD_SHOW: 487 bIterate = 0; 488 show_tdb(arg1, arg1len); 489 return 0; 490 case CMD_KEYS: 491 tdb_traverse(tdb, print_key, NULL); 492 return 0; 493 case CMD_HEXKEYS: 494 tdb_traverse(tdb, print_hexkey, NULL); 495 return 0; 496 case CMD_DELETE: 497 bIterate = 0; 498 delete_tdb(arg1,arg1len); 499 return 0; 500 case CMD_LIST_HASH_FREE: 501 tdb_dump_all(tdb); 502 return 0; 503 case CMD_LIST_FREE: 504 tdb_printfreelist(tdb); 505 return 0; 506 case CMD_INFO: 507 info_tdb(); 508 return 0; 509 case CMD_FIRST: 510 bIterate = 1; 511 first_record(tdb, &iterate_kbuf); 512 return 0; 513 case CMD_NEXT: 514 if (bIterate) 515 next_record(tdb, &iterate_kbuf); 516 return 0; 517 case CMD_HELP: 518 help(); 519 return 0; 520 case CMD_CREATE_TDB: 521 case CMD_OPEN_TDB: 522 case CMD_SYSTEM: 523 case CMD_QUIT: 524 /* 525 * unhandled commands. cases included here to avoid compiler 526 * warnings. 527 */ 528 return 0; 529 } 530 } 531 532 return 0; 533 } 534 535 static char *convert_string(char *instring, size_t *sizep) 536 { 537 size_t length = 0; 538 char *outp, *inp; 539 char temp[3]; 540 541 542 outp = inp = instring; 543 544 while (*inp) { 545 if (*inp == '\\') { 546 inp++; 547 if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) { 548 temp[0] = *inp++; 549 temp[1] = '\0'; 550 if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) { 551 temp[1] = *inp++; 552 temp[2] = '\0'; 553 } 554 *outp++ = (char)strtol((const char *)temp,NULL,16); 555 } else { 556 *outp++ = *inp++; 557 } 558 } else { 559 *outp++ = *inp++; 560 } 561 length++; 562 } 563 *sizep = length; 564 return instring; 565 } 566 567 int main(int argc, char *argv[]) 568 { 569 cmdname = ""; 570 arg1 = NULL; 571 arg1len = 0; 572 arg2 = NULL; 573 arg2len = 0; 574 575 if (argv[1]) { 576 cmdname = "open"; 577 arg1 = argv[1]; 578 do_command(); 579 cmdname = ""; 580 arg1 = NULL; 581 } 582 583 switch (argc) { 584 case 1: 585 case 2: 586 /* Interactive mode */ 587 while ((cmdname = tdb_getline("tdb> "))) { 588 arg2 = arg1 = NULL; 589 if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) { 590 arg1++; 591 arg2 = arg1; 592 while (*arg2) { 593 if (*arg2 == ' ') { 594 *arg2++ = '\0'; 595 break; 596 } 597 if ((*arg2++ == '\\') && (*arg2 == ' ')) { 598 arg2++; 599 } 600 } 601 } 602 if (arg1) arg1 = convert_string(arg1,&arg1len); 603 if (arg2) arg2 = convert_string(arg2,&arg2len); 604 if (do_command()) break; 605 } 606 break; 607 case 5: 608 arg2 = convert_string(argv[4],&arg2len); 609 case 4: 610 arg1 = convert_string(argv[3],&arg1len); 611 case 3: 612 cmdname = argv[2]; 613 default: 614 do_command(); 615 break; 616 } 617 618 if (tdb) tdb_close(tdb); 619 620 return 0; 621 } 622