tdb2: rearrange log function to put data arg at the end.
[ccan] / ccan / tdb2 / tools / tdbtool.c
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 3 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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <ccan/tdb2/tdb2.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdarg.h>
34
35 static int do_command(void);
36 const char *cmdname;
37 char *arg1, *arg2;
38 size_t arg1len, arg2len;
39 int bIterate = 0;
40 char *line;
41 TDB_DATA iterate_kbuf;
42 char cmdline[1024];
43 static int disable_mmap;
44
45 enum commands {
46         CMD_CREATE_TDB,
47         CMD_OPEN_TDB,
48         CMD_TRANSACTION_START,
49         CMD_TRANSACTION_COMMIT,
50         CMD_TRANSACTION_CANCEL,
51         CMD_ERASE,
52         CMD_DUMP,
53         CMD_INSERT,
54         CMD_MOVE,
55         CMD_STORE,
56         CMD_SHOW,
57         CMD_KEYS,
58         CMD_HEXKEYS,
59         CMD_DELETE,
60 #if 0
61         CMD_LIST_HASH_FREE,
62         CMD_LIST_FREE,
63 #endif
64         CMD_INFO,
65         CMD_MMAP,
66         CMD_SPEED,
67         CMD_FIRST,
68         CMD_NEXT,
69         CMD_SYSTEM,
70         CMD_CHECK,
71         CMD_QUIT,
72         CMD_HELP
73 };
74
75 typedef struct {
76         const char *name;
77         enum commands cmd;
78 } COMMAND_TABLE;
79
80 COMMAND_TABLE cmd_table[] = {
81         {"create",      CMD_CREATE_TDB},
82         {"open",        CMD_OPEN_TDB},
83 #if 0
84         {"transaction_start",   CMD_TRANSACTION_START},
85         {"transaction_commit",  CMD_TRANSACTION_COMMIT},
86         {"transaction_cancel",  CMD_TRANSACTION_CANCEL},
87 #endif
88         {"erase",       CMD_ERASE},
89         {"dump",        CMD_DUMP},
90         {"insert",      CMD_INSERT},
91         {"move",        CMD_MOVE},
92         {"store",       CMD_STORE},
93         {"show",        CMD_SHOW},
94         {"keys",        CMD_KEYS},
95         {"hexkeys",     CMD_HEXKEYS},
96         {"delete",      CMD_DELETE},
97 #if 0
98         {"list",        CMD_LIST_HASH_FREE},
99         {"free",        CMD_LIST_FREE},
100 #endif
101         {"info",        CMD_INFO},
102         {"speed",       CMD_SPEED},
103         {"mmap",        CMD_MMAP},
104         {"first",       CMD_FIRST},
105         {"1",           CMD_FIRST},
106         {"next",        CMD_NEXT},
107         {"n",           CMD_NEXT},
108         {"check",       CMD_CHECK},
109         {"quit",        CMD_QUIT},
110         {"q",           CMD_QUIT},
111         {"!",           CMD_SYSTEM},
112         {NULL,          CMD_HELP}
113 };
114
115 struct timeval tp1,tp2;
116
117 static void _start_timer(void)
118 {
119         gettimeofday(&tp1,NULL);
120 }
121
122 static double _end_timer(void)
123 {
124         gettimeofday(&tp2,NULL);
125         return((tp2.tv_sec - tp1.tv_sec) + 
126                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
127 }
128
129 static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
130                     const char *message, void *priv)
131 {
132         fputs(message, stderr);
133 }
134
135 /* a tdb tool for manipulating a tdb database */
136
137 static struct tdb_context *tdb;
138
139 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
140 static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
141 static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
142
143 static void print_asc(const char *buf,int len)
144 {
145         int i;
146
147         /* We're probably printing ASCII strings so don't try to display
148            the trailing NULL character. */
149
150         if (buf[len - 1] == 0)
151                 len--;
152
153         for (i=0;i<len;i++)
154                 printf("%c",isprint(buf[i])?buf[i]:'.');
155 }
156
157 static void print_data(const char *buf,int len)
158 {
159         int i=0;
160         if (len<=0) return;
161         printf("[%03X] ",i);
162         for (i=0;i<len;) {
163                 printf("%02X ",(int)((unsigned char)buf[i]));
164                 i++;
165                 if (i%8 == 0) printf(" ");
166                 if (i%16 == 0) {      
167                         print_asc(&buf[i-16],8); printf(" ");
168                         print_asc(&buf[i-8],8); printf("\n");
169                         if (i<len) printf("[%03X] ",i);
170                 }
171         }
172         if (i%16) {
173                 int n;
174                 
175                 n = 16 - (i%16);
176                 printf(" ");
177                 if (n>8) printf(" ");
178                 while (n--) printf("   ");
179                 
180                 n = i%16;
181                 if (n > 8) n = 8;
182                 print_asc(&buf[i-(i%16)],n); printf(" ");
183                 n = (i%16) - n;
184                 if (n>0) print_asc(&buf[i-n],n); 
185                 printf("\n");    
186         }
187 }
188
189 static void help(void)
190 {
191         printf("\n"
192 "tdbtool: \n"
193 "  create    dbname     : create a database\n"
194 "  open      dbname     : open an existing database\n"
195 "  openjh    dbname     : open an existing database (jenkins hash)\n"
196 "  transaction_start    : start a transaction\n"
197 "  transaction_commit   : commit a transaction\n"
198 "  transaction_cancel   : cancel a transaction\n"
199 "  erase                : erase the database\n"
200 "  dump                 : dump the database as strings\n"
201 "  keys                 : dump the database keys as strings\n"
202 "  hexkeys              : dump the database keys as hex values\n"
203 "  info                 : print summary info about the database\n"
204 "  insert    key  data  : insert a record\n"
205 "  move      key  file  : move a record to a destination tdb\n"
206 "  store     key  data  : store a record (replace)\n"
207 "  show      key        : show a record by key\n"
208 "  delete    key        : delete a record by key\n"
209 #if 0
210 "  list                 : print the database hash table and freelist\n"
211 "  free                 : print the database freelist\n"
212 #endif
213 "  check                : check the integrity of an opened database\n"
214 "  speed                : perform speed tests on the database\n"
215 "  ! command            : execute system command\n"
216 "  1 | first            : print the first record\n"
217 "  n | next             : print the next record\n"
218 "  q | quit             : terminate\n"
219 "  \\n                   : repeat 'next' command\n"
220 "\n");
221 }
222
223 static void terror(enum TDB_ERROR err, const char *why)
224 {
225         if (err != TDB_SUCCESS)
226                 printf("%s:%s\n", tdb_errorstr(err), why);
227         else
228                 printf("%s\n", why);
229 }
230
231 static void create_tdb(const char *tdbname)
232 {
233         union tdb_attribute log_attr;
234         log_attr.base.attr = TDB_ATTRIBUTE_LOG;
235         log_attr.base.next = NULL;
236         log_attr.log.fn = tdb_log;
237
238         if (tdb) tdb_close(tdb);
239         tdb = tdb_open(tdbname, (disable_mmap?TDB_NOMMAP:0),
240                        O_RDWR | O_CREAT | O_TRUNC, 0600, &log_attr);
241         if (!tdb) {
242                 printf("Could not create %s: %s\n", tdbname, strerror(errno));
243         }
244 }
245
246 static void open_tdb(const char *tdbname)
247 {
248         union tdb_attribute log_attr;
249         log_attr.base.attr = TDB_ATTRIBUTE_LOG;
250         log_attr.base.next = NULL;
251         log_attr.log.fn = tdb_log;
252
253         if (tdb) tdb_close(tdb);
254         tdb = tdb_open(tdbname, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
255                        &log_attr);
256         if (!tdb) {
257                 printf("Could not open %s: %s\n", tdbname, strerror(errno));
258         }
259 }
260
261 static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
262 {
263         TDB_DATA key, dbuf;
264         enum TDB_ERROR ecode;
265
266         if ((keyname == NULL) || (keylen == 0)) {
267                 terror(TDB_SUCCESS, "need key");
268                 return;
269         }
270
271         key.dptr = (unsigned char *)keyname;
272         key.dsize = keylen;
273         dbuf.dptr = (unsigned char *)data;
274         dbuf.dsize = datalen;
275
276         ecode = tdb_store(tdb, key, dbuf, TDB_INSERT);
277         if (ecode) {
278                 terror(ecode, "insert failed");
279         }
280 }
281
282 static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
283 {
284         TDB_DATA key, dbuf;
285         enum TDB_ERROR ecode;
286
287         if ((keyname == NULL) || (keylen == 0)) {
288                 terror(TDB_SUCCESS, "need key");
289                 return;
290         }
291
292         if ((data == NULL) || (datalen == 0)) {
293                 terror(TDB_SUCCESS, "need data");
294                 return;
295         }
296
297         key.dptr = (unsigned char *)keyname;
298         key.dsize = keylen;
299         dbuf.dptr = (unsigned char *)data;
300         dbuf.dsize = datalen;
301
302         printf("Storing key:\n");
303         print_rec(tdb, key, dbuf, NULL);
304
305         ecode = tdb_store(tdb, key, dbuf, TDB_REPLACE);
306         if (ecode) {
307                 terror(ecode, "store failed");
308         }
309 }
310
311 static void show_tdb(char *keyname, size_t keylen)
312 {
313         TDB_DATA key, dbuf;
314         enum TDB_ERROR ecode;
315
316         if ((keyname == NULL) || (keylen == 0)) {
317                 terror(TDB_SUCCESS, "need key");
318                 return;
319         }
320
321         key.dptr = (unsigned char *)keyname;
322         key.dsize = keylen;
323
324         ecode = tdb_fetch(tdb, key, &dbuf);
325         if (ecode) {
326                 terror(ecode, "fetch failed");
327                 return;
328         }
329         
330         print_rec(tdb, key, dbuf, NULL);
331         
332         free( dbuf.dptr );
333 }
334
335 static void delete_tdb(char *keyname, size_t keylen)
336 {
337         TDB_DATA key;
338         enum TDB_ERROR ecode;
339
340         if ((keyname == NULL) || (keylen == 0)) {
341                 terror(TDB_SUCCESS, "need key");
342                 return;
343         }
344
345         key.dptr = (unsigned char *)keyname;
346         key.dsize = keylen;
347
348         ecode = tdb_delete(tdb, key);
349         if (ecode) {
350                 terror(ecode, "delete failed");
351         }
352 }
353
354 static void move_rec(char *keyname, size_t keylen, char* tdbname)
355 {
356         TDB_DATA key, dbuf;
357         struct tdb_context *dst_tdb;
358         enum TDB_ERROR ecode;
359
360         if ((keyname == NULL) || (keylen == 0)) {
361                 terror(TDB_SUCCESS, "need key");
362                 return;
363         }
364
365         if ( !tdbname ) {
366                 terror(TDB_SUCCESS, "need destination tdb name");
367                 return;
368         }
369
370         key.dptr = (unsigned char *)keyname;
371         key.dsize = keylen;
372
373         ecode = tdb_fetch(tdb, key, &dbuf);
374         if (ecode) {
375                 terror(ecode, "fetch failed");
376                 return;
377         }
378         
379         print_rec(tdb, key, dbuf, NULL);
380         
381         dst_tdb = tdb_open(tdbname, 0, O_RDWR, 0600, NULL);
382         if ( !dst_tdb ) {
383                 terror(TDB_SUCCESS, "unable to open destination tdb");
384                 return;
385         }
386         
387         ecode = tdb_store( dst_tdb, key, dbuf, TDB_REPLACE);
388         if (ecode)
389                 terror(ecode, "failed to move record");
390         else
391                 printf("record moved\n");
392         
393         tdb_close( dst_tdb );
394 }
395
396 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
397 {
398         printf("\nkey %d bytes\n", (int)key.dsize);
399         print_asc((const char *)key.dptr, key.dsize);
400         printf("\ndata %d bytes\n", (int)dbuf.dsize);
401         print_data((const char *)dbuf.dptr, dbuf.dsize);
402         return 0;
403 }
404
405 static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
406 {
407         printf("key %d bytes: ", (int)key.dsize);
408         print_asc((const char *)key.dptr, key.dsize);
409         printf("\n");
410         return 0;
411 }
412
413 static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
414 {
415         printf("key %d bytes\n", (int)key.dsize);
416         print_data((const char *)key.dptr, key.dsize);
417         printf("\n");
418         return 0;
419 }
420
421 static int total_bytes;
422
423 static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
424 {
425         total_bytes += dbuf.dsize;
426         return 0;
427 }
428
429 static void info_tdb(void)
430 {
431         enum TDB_ERROR ecode;
432         char *summary;
433
434         ecode = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &summary);
435
436         if (ecode) {
437                 terror(ecode, "Getting summary");
438         } else {
439                 printf("%s", summary);
440                 free(summary);
441         }
442 }
443
444 static void speed_tdb(const char *tlimit)
445 {
446         unsigned timelimit = tlimit?atoi(tlimit):0;
447         double t;
448         int ops;
449         if (timelimit == 0) timelimit = 5;
450
451         ops = 0;
452         printf("Testing store speed for %u seconds\n", timelimit);
453         _start_timer();
454         do {
455                 long int r = random();
456                 TDB_DATA key, dbuf;
457                 key = tdb_mkdata("store test", strlen("store test"));
458                 dbuf.dptr = (unsigned char *)&r;
459                 dbuf.dsize = sizeof(r);
460                 tdb_store(tdb, key, dbuf, TDB_REPLACE);
461                 t = _end_timer();
462                 ops++;
463         } while (t < timelimit);
464         printf("%10.3f ops/sec\n", ops/t);
465
466         ops = 0;
467         printf("Testing fetch speed for %u seconds\n", timelimit);
468         _start_timer();
469         do {
470                 long int r = random();
471                 TDB_DATA key, dbuf;
472                 key = tdb_mkdata("store test", strlen("store test"));
473                 dbuf.dptr = (unsigned char *)&r;
474                 dbuf.dsize = sizeof(r);
475                 tdb_fetch(tdb, key, &dbuf);
476                 t = _end_timer();
477                 ops++;
478         } while (t < timelimit);
479         printf("%10.3f ops/sec\n", ops/t);
480
481         ops = 0;
482         printf("Testing transaction speed for %u seconds\n", timelimit);
483         _start_timer();
484         do {
485                 long int r = random();
486                 TDB_DATA key, dbuf;
487                 key = tdb_mkdata("transaction test", strlen("transaction test"));
488                 dbuf.dptr = (unsigned char *)&r;
489                 dbuf.dsize = sizeof(r);
490                 tdb_transaction_start(tdb);
491                 tdb_store(tdb, key, dbuf, TDB_REPLACE);
492                 tdb_transaction_commit(tdb);
493                 t = _end_timer();
494                 ops++;
495         } while (t < timelimit);
496         printf("%10.3f ops/sec\n", ops/t);
497
498         ops = 0;
499         printf("Testing traverse speed for %u seconds\n", timelimit);
500         _start_timer();
501         do {
502                 tdb_traverse(tdb, traverse_fn, NULL);
503                 t = _end_timer();
504                 ops++;
505         } while (t < timelimit);
506         printf("%10.3f ops/sec\n", ops/t);
507 }
508
509 static void toggle_mmap(void)
510 {
511         disable_mmap = !disable_mmap;
512         if (disable_mmap) {
513                 printf("mmap is disabled\n");
514         } else {
515                 printf("mmap is enabled\n");
516         }
517 }
518
519 static char *tdb_getline(const char *prompt)
520 {
521         static char thisline[1024];
522         char *p;
523         fputs(prompt, stdout);
524         thisline[0] = 0;
525         p = fgets(thisline, sizeof(thisline)-1, stdin);
526         if (p) p = strchr(p, '\n');
527         if (p) *p = 0;
528         return p?thisline:NULL;
529 }
530
531 static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
532                      void *state)
533 {
534     return tdb_delete(the_tdb, key);
535 }
536
537 static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
538 {
539         TDB_DATA dbuf;
540         enum TDB_ERROR ecode;
541         ecode = tdb_firstkey(the_tdb, pkey);
542         if (!ecode)
543                 ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
544         if (ecode) terror(ecode, "fetch failed");
545         else {
546                 print_rec(the_tdb, *pkey, dbuf, NULL);
547         }
548 }
549
550 static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
551 {
552         TDB_DATA dbuf;
553         enum TDB_ERROR ecode;
554         ecode = tdb_nextkey(the_tdb, pkey);
555
556         if (!ecode)
557                 ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
558         if (ecode) 
559                 terror(ecode, "fetch failed");
560         else
561                 print_rec(the_tdb, *pkey, dbuf, NULL);
562 }
563
564 static void check_db(struct tdb_context *the_tdb)
565 {
566         if (!the_tdb) {
567                 printf("Error: No database opened!\n");
568         } else {
569                 if (tdb_check(the_tdb, NULL, NULL) != 0)
570                         printf("Integrity check for the opened database failed.\n");
571                 else
572                         printf("Database integrity is OK.\n");
573         }
574 }
575
576 static int do_command(void)
577 {
578         COMMAND_TABLE *ctp = cmd_table;
579         enum commands mycmd = CMD_HELP;
580         int cmd_len;
581
582         if (cmdname && strlen(cmdname) == 0) {
583                 mycmd = CMD_NEXT;
584         } else {
585                 while (ctp->name) {
586                         cmd_len = strlen(ctp->name);
587                         if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
588                                 mycmd = ctp->cmd;
589                                 break;
590                         }
591                         ctp++;
592                 }
593         }
594
595         switch (mycmd) {
596         case CMD_CREATE_TDB:
597                 bIterate = 0;
598                 create_tdb(arg1);
599                 return 0;
600         case CMD_OPEN_TDB:
601                 bIterate = 0;
602                 open_tdb(arg1);
603                 return 0;
604         case CMD_SYSTEM:
605                 /* Shell command */
606                 if (system(arg1) == -1) {
607                         terror(TDB_SUCCESS, "system() call failed\n");
608                 }
609                 return 0;
610         case CMD_QUIT:
611                 return 1;
612         default:
613                 /* all the rest require a open database */
614                 if (!tdb) {
615                         bIterate = 0;
616                         terror(TDB_SUCCESS, "database not open");
617                         help();
618                         return 0;
619                 }
620                 switch (mycmd) {
621                 case CMD_TRANSACTION_START:
622                         bIterate = 0;
623                         tdb_transaction_start(tdb);
624                         return 0;
625                 case CMD_TRANSACTION_COMMIT:
626                         bIterate = 0;
627                         tdb_transaction_commit(tdb);
628                         return 0;
629                 case CMD_TRANSACTION_CANCEL:
630                         bIterate = 0;
631                         tdb_transaction_cancel(tdb);
632                         return 0;
633                 case CMD_ERASE:
634                         bIterate = 0;
635                         tdb_traverse(tdb, do_delete_fn, NULL);
636                         return 0;
637                 case CMD_DUMP:
638                         bIterate = 0;
639                         tdb_traverse(tdb, print_rec, NULL);
640                         return 0;
641                 case CMD_INSERT:
642                         bIterate = 0;
643                         insert_tdb(arg1, arg1len,arg2,arg2len);
644                         return 0;
645                 case CMD_MOVE:
646                         bIterate = 0;
647                         move_rec(arg1,arg1len,arg2);
648                         return 0;
649                 case CMD_STORE:
650                         bIterate = 0;
651                         store_tdb(arg1,arg1len,arg2,arg2len);
652                         return 0;
653                 case CMD_SHOW:
654                         bIterate = 0;
655                         show_tdb(arg1, arg1len);
656                         return 0;
657                 case CMD_KEYS:
658                         tdb_traverse(tdb, print_key, NULL);
659                         return 0;
660                 case CMD_HEXKEYS:
661                         tdb_traverse(tdb, print_hexkey, NULL);
662                         return 0;
663                 case CMD_DELETE:
664                         bIterate = 0;
665                         delete_tdb(arg1,arg1len);
666                         return 0;
667 #if 0
668                 case CMD_LIST_HASH_FREE:
669                         tdb_dump_all(tdb);
670                         return 0;
671                 case CMD_LIST_FREE:
672                         tdb_printfreelist(tdb);
673                         return 0;
674 #endif
675                 case CMD_INFO:
676                         info_tdb();
677                         return 0;
678                 case CMD_SPEED:
679                         speed_tdb(arg1);
680                         return 0;
681                 case CMD_MMAP:
682                         toggle_mmap();
683                         return 0;
684                 case CMD_FIRST:
685                         bIterate = 1;
686                         first_record(tdb, &iterate_kbuf);
687                         return 0;
688                 case CMD_NEXT:
689                         if (bIterate)
690                                 next_record(tdb, &iterate_kbuf);
691                         return 0;
692                 case CMD_CHECK:
693                         check_db(tdb);
694                         return 0;
695                 case CMD_HELP:
696                         help();
697                         return 0;
698                 case CMD_CREATE_TDB:
699                 case CMD_OPEN_TDB:
700                 case CMD_SYSTEM:
701                 case CMD_QUIT:
702                         /*
703                          * unhandled commands.  cases included here to avoid compiler
704                          * warnings.
705                          */
706                         return 0;
707                 }
708         }
709
710         return 0;
711 }
712
713 static char *convert_string(char *instring, size_t *sizep)
714 {
715         size_t length = 0;
716         char *outp, *inp;
717         char temp[3];
718
719         outp = inp = instring;
720
721         while (*inp) {
722                 if (*inp == '\\') {
723                         inp++;
724                         if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
725                                 temp[0] = *inp++;
726                                 temp[1] = '\0';
727                                 if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
728                                         temp[1] = *inp++;
729                                         temp[2] = '\0';
730                                 }
731                                 *outp++ = (char)strtol((const char *)temp,NULL,16);
732                         } else {
733                                 *outp++ = *inp++;
734                         }
735                 } else {
736                         *outp++ = *inp++;
737                 }
738                 length++;
739         }
740         *sizep = length;
741         return instring;
742 }
743
744 int main(int argc, char *argv[])
745 {
746         cmdname = "";
747         arg1 = NULL;
748         arg1len = 0;
749         arg2 = NULL;
750         arg2len = 0;
751
752         if (argv[1]) {
753                 cmdname = "open";
754                 arg1 = argv[1];
755                 do_command();
756                 cmdname =  "";
757                 arg1 = NULL;
758         }
759
760         switch (argc) {
761         case 1:
762         case 2:
763                 /* Interactive mode */
764                 while ((cmdname = tdb_getline("tdb> "))) {
765                         arg2 = arg1 = NULL;
766                         if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
767                                 arg1++;
768                                 arg2 = arg1;
769                                 while (*arg2) {
770                                         if (*arg2 == ' ') {
771                                                 *arg2++ = '\0';
772                                                 break;
773                                         }
774                                         if ((*arg2++ == '\\') && (*arg2 == ' ')) {
775                                                 arg2++;
776                                         }
777                                 }
778                         }
779                         if (arg1) arg1 = convert_string(arg1,&arg1len);
780                         if (arg2) arg2 = convert_string(arg2,&arg2len);
781                         if (do_command()) break;
782                 }
783                 break;
784         case 5:
785                 arg2 = convert_string(argv[4],&arg2len);
786         case 4:
787                 arg1 = convert_string(argv[3],&arg1len);
788         case 3:
789                 cmdname = argv[2];
790         default:
791                 do_command();
792                 break;
793         }
794
795         if (tdb) tdb_close(tdb);
796
797         return 0;
798 }