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