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 "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