Initial import
[samba] / source / 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(const 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(const 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         if ((keyname == NULL) || (keylen == 0)) {
236                 terror("need key");
237                 return;
238         }
239
240         key.dptr = keyname;
241         key.dsize = keylen;
242         dbuf.dptr = data;
243         dbuf.dsize = datalen;
244
245         if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
246                 terror("insert failed");
247         }
248 }
249
250 static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
251 {
252         TDB_DATA key, dbuf;
253
254         if ((keyname == NULL) || (keylen == 0)) {
255                 terror("need key");
256                 return;
257         }
258
259         if ((data == NULL) || (datalen == 0)) {
260                 terror("need data");
261                 return;
262         }
263
264         key.dptr = keyname;
265         key.dsize = keylen;
266         dbuf.dptr = data;
267         dbuf.dsize = datalen;
268
269         printf("Storing key:\n");
270         print_rec(tdb, key, dbuf, NULL);
271
272         if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
273                 terror("store failed");
274         }
275 }
276
277 static void show_tdb(char *keyname, size_t keylen)
278 {
279         TDB_DATA key, dbuf;
280
281         if ((keyname == NULL) || (keylen == 0)) {
282                 terror("need key");
283                 return;
284         }
285
286         key.dptr = keyname;
287         key.dsize = keylen;
288
289         dbuf = tdb_fetch(tdb, key);
290         if (!dbuf.dptr) {
291             terror("fetch failed");
292             return;
293         }
294         
295         print_rec(tdb, key, dbuf, NULL);
296         
297         free( dbuf.dptr );
298         
299         return;
300 }
301
302 static void delete_tdb(char *keyname, size_t keylen)
303 {
304         TDB_DATA key;
305
306         if ((keyname == NULL) || (keylen == 0)) {
307                 terror("need key");
308                 return;
309         }
310
311         key.dptr = keyname;
312         key.dsize = keylen;
313
314         if (tdb_delete(tdb, key) != 0) {
315                 terror("delete failed");
316         }
317 }
318
319 static void move_rec(char *keyname, size_t keylen, char* tdbname)
320 {
321         TDB_DATA key, dbuf;
322         TDB_CONTEXT *dst_tdb;
323
324         if ((keyname == NULL) || (keylen == 0)) {
325                 terror("need key");
326                 return;
327         }
328
329         if ( !tdbname ) {
330                 terror("need destination tdb name");
331                 return;
332         }
333
334         key.dptr = keyname;
335         key.dsize = keylen;
336
337         dbuf = tdb_fetch(tdb, key);
338         if (!dbuf.dptr) {
339                 terror("fetch failed");
340                 return;
341         }
342         
343         print_rec(tdb, key, dbuf, NULL);
344         
345         dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
346         if ( !dst_tdb ) {
347                 terror("unable to open destination tdb");
348                 return;
349         }
350         
351         if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
352                 terror("failed to move record");
353         }
354         else
355                 printf("record moved\n");
356         
357         tdb_close( dst_tdb );
358         
359         return;
360 }
361
362 static int print_conn_key(TDB_DATA key)
363 {
364         printf( "\nkey %d bytes\n", (int)key.dsize);
365         printf( "pid    =%5d   ", ((connections_key*)key.dptr)->pid);
366         printf( "cnum   =%10d  ", ((connections_key*)key.dptr)->cnum);
367         printf( "name   =[%s]\n", ((connections_key*)key.dptr)->name);
368         return 0;
369 }
370
371 static int print_conn_data(TDB_DATA dbuf)
372 {
373         printf( "\ndata %d bytes\n", (int)dbuf.dsize);
374         printf( "pid    =%5d   ", ((connections_data*)dbuf.dptr)->pid);
375         printf( "cnum   =%10d  ", ((connections_data*)dbuf.dptr)->cnum);
376         printf( "name   =[%s]\n", ((connections_data*)dbuf.dptr)->name);
377         
378         printf( "uid    =%5d   ",  ((connections_data*)dbuf.dptr)->uid);
379         printf( "addr   =[%s]\n", ((connections_data*)dbuf.dptr)->addr);
380         printf( "gid    =%5d   ",  ((connections_data*)dbuf.dptr)->gid);
381         printf( "machine=[%s]\n", ((connections_data*)dbuf.dptr)->machine);
382         printf( "start  = %s\n",   ctime(&((connections_data*)dbuf.dptr)->start));
383         printf( "magic  = 0x%x ",   ((connections_data*)dbuf.dptr)->magic);
384         printf( "flags  = 0x%x\n",  ((connections_data*)dbuf.dptr)->bcast_msg_flags);
385         return 0;
386 }
387
388 static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
389 {
390         if (do_connections && (dbuf.dsize == sizeof(connections_data)))
391                 print_crec(the_tdb, key, dbuf, state);
392         else
393                 print_arec(the_tdb, key, dbuf, state);
394         return 0;
395 }
396
397 static int print_crec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
398 {
399         print_conn_key(key);
400         print_conn_data(dbuf);
401         return 0;
402 }
403
404 static int print_arec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
405 {
406         printf("\nkey %d bytes\n", (int)key.dsize);
407         print_asc(key.dptr, key.dsize);
408         printf("\ndata %d bytes\n", (int)dbuf.dsize);
409         print_data(dbuf.dptr, dbuf.dsize);
410         return 0;
411 }
412
413 static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
414 {
415         printf("key %d bytes: ", (int)key.dsize);
416         print_asc(key.dptr, key.dsize);
417         printf("\n");
418         return 0;
419 }
420
421 static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
422 {
423         printf("key %d bytes\n", (int)key.dsize);
424         print_data(key.dptr, key.dsize);
425         printf("\n");
426         return 0;
427 }
428
429 static int total_bytes;
430
431 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
432 {
433         total_bytes += dbuf.dsize;
434         return 0;
435 }
436
437 static void info_tdb(void)
438 {
439         int count;
440         total_bytes = 0;
441         if ((count = tdb_traverse(tdb, traverse_fn, NULL)) == -1)
442                 printf("Error = %s\n", tdb_errorstr(tdb));
443         else
444                 printf("%d records totalling %d bytes\n", count, total_bytes);
445 }
446
447 static char *tdb_getline(const char *prompt)
448 {
449         static char thisline[1024];
450         char *p;
451         fputs(prompt, stdout);
452         thisline[0] = 0;
453         p = fgets(thisline, sizeof(thisline)-1, stdin);
454         if (p) p = strchr(p, '\n');
455         if (p) *p = 0;
456         return p?thisline:NULL;
457 }
458
459 static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
460                      void *state)
461 {
462     return tdb_delete(the_tdb, key);
463 }
464
465 static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
466 {
467         TDB_DATA dbuf;
468         *pkey = tdb_firstkey(the_tdb);
469         
470         dbuf = tdb_fetch(the_tdb, *pkey);
471         if (!dbuf.dptr) terror("fetch failed");
472         else {
473                 print_rec(the_tdb, *pkey, dbuf, NULL);
474         }
475 }
476
477 static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
478 {
479         TDB_DATA dbuf;
480         *pkey = tdb_nextkey(the_tdb, *pkey);
481         
482         dbuf = tdb_fetch(the_tdb, *pkey);
483         if (!dbuf.dptr) 
484                 terror("fetch failed");
485         else
486                 print_rec(the_tdb, *pkey, dbuf, NULL);
487 }
488
489 static int do_command(void)
490 {
491         COMMAND_TABLE *ctp = cmd_table;
492         enum commands mycmd = CMD_HELP;
493         int cmd_len;
494
495         do_connections = 0;
496
497         if (cmdname && strlen(cmdname) == 0) {
498             mycmd = CMD_NEXT;
499         } else {
500             while (ctp->name) {
501                 cmd_len = strlen(ctp->name);
502                 if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
503                         mycmd = ctp->cmd;
504                         break;
505                 }
506                 ctp++;
507             }
508         }
509
510         switch (mycmd) {
511         case CMD_CREATE_TDB:
512             bIterate = 0;
513             create_tdb(arg1);
514             return 0;
515         case CMD_OPEN_TDB:
516             bIterate = 0;
517             open_tdb(arg1);
518             return 0;
519         case CMD_SYSTEM:
520             /* Shell command */
521             system(arg1);
522             return 0;
523         case CMD_QUIT:
524             return 1;
525         default:
526             /* all the rest require a open database */
527             if (!tdb) {
528                 bIterate = 0;
529                 terror("database not open");
530                 help();
531                 return 0;
532             }
533             switch (mycmd) {
534             case CMD_ERASE:
535                 bIterate = 0;
536                 tdb_traverse(tdb, do_delete_fn, NULL);
537                 return 0;
538             case CMD_DUMP:
539                 bIterate = 0;
540                 tdb_traverse(tdb, print_rec, NULL);
541                 return 0;
542             case CMD_CDUMP:
543                 do_connections = 1;
544                 bIterate = 0;
545                 tdb_traverse(tdb, print_rec, NULL);
546                 return 0;
547             case CMD_INSERT:
548                 bIterate = 0;
549                 insert_tdb(arg1, arg1len,arg2,arg2len);
550                 return 0;
551             case CMD_MOVE:
552                 bIterate = 0;
553                 move_rec(arg1,arg1len,arg2);
554                 return 0;
555             case CMD_STORE:
556                 bIterate = 0;
557                 store_tdb(arg1,arg1len,arg2,arg2len);
558                 return 0;
559             case CMD_SHOW:
560                 bIterate = 0;
561                 show_tdb(arg1, arg1len);
562                 return 0;
563             case CMD_KEYS:
564                 tdb_traverse(tdb, print_key, NULL);
565                 return 0;
566             case CMD_HEXKEYS:
567                 tdb_traverse(tdb, print_hexkey, NULL);
568                 return 0;
569             case CMD_DELETE:
570                 bIterate = 0;
571                 delete_tdb(arg1,arg1len);
572                 return 0;
573             case CMD_LIST_HASH_FREE:
574                 tdb_dump_all(tdb);
575                 return 0;
576             case CMD_LIST_FREE:
577                 tdb_printfreelist(tdb);
578                 return 0;
579             case CMD_INFO:
580                 info_tdb();
581                 return 0;
582             case CMD_FIRST:
583                 bIterate = 1;
584                 first_record(tdb, &iterate_kbuf);
585                 return 0;
586             case CMD_NEXT:
587                if (bIterate)
588                   next_record(tdb, &iterate_kbuf);
589                 return 0;
590             case CMD_HELP:
591                 help();
592                 return 0;
593             case CMD_CREATE_TDB:
594             case CMD_OPEN_TDB:
595             case CMD_SYSTEM:
596             case CMD_QUIT:
597                 /*
598                  * unhandled commands.  cases included here to avoid compiler
599                  * warnings.
600                  */
601                 return 0;
602             }
603         }
604
605         return 0;
606 }
607
608 static char *convert_string(char *instring, size_t *sizep)
609 {
610     size_t length = 0;
611     char *outp, *inp;
612     char temp[3];
613     
614
615     outp = inp = instring;
616
617     while (*inp) {
618         if (*inp == '\\') {
619             inp++;
620             if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
621                 temp[0] = *inp++;
622                 temp[1] = '\0';
623                 if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
624                     temp[1] = *inp++;
625                     temp[2] = '\0';
626                 }
627                 *outp++ = (char)strtol((const char *)temp,NULL,16);
628             } else {
629                 *outp++ = *inp++;
630             }
631         } else {
632             *outp++ = *inp++;
633         }
634         length++;
635     }
636     *sizep = length;
637     return instring;
638 }
639
640 int main(int argc, char *argv[])
641 {
642     cmdname = (char *) "";
643     arg1 = NULL;
644     arg1len = 0;
645     arg2 = NULL;
646     arg2len = 0;
647
648     if (argv[1]) {
649         cmdname = (char *) "open";
650         arg1 = argv[1];
651         do_command();
652         cmdname = (char *) "";
653         arg1 = NULL;
654     }
655
656     switch (argc) {
657         case 1:
658         case 2:
659             /* Interactive mode */
660             while ((cmdname = tdb_getline("tdb> "))) {
661                 arg2 = arg1 = NULL;
662                 if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
663                     arg1++;
664                     arg2 = arg1;
665                     while (*arg2) {
666                         if (*arg2 == ' ') {
667                             *arg2++ = '\0';
668                             break;
669                         }
670                         if ((*arg2++ == '\\') && (*arg2 == ' ')) {
671                             arg2++;
672                         }
673                     }
674                 }
675                 if (arg1) arg1 = convert_string(arg1,&arg1len);
676                 if (arg2) arg2 = convert_string(arg2,&arg2len);
677                 if (do_command()) break;
678             }
679             break;
680         case 5:
681             arg2 = convert_string(argv[4],&arg2len);
682         case 4:
683             arg1 = convert_string(argv[3],&arg1len);
684         case 3:
685             cmdname = argv[2];
686         default:
687             do_command();
688             break;
689     }
690
691     if (tdb) tdb_close(tdb);
692
693     return 0;
694 }