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