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