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