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