r16774: This patch modifies the tdb API to allow the logging function to be used
[ira/wip.git] / source / 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 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 <stdarg.h>
38 #include "tdb.h"
39
40 /* a tdb tool for manipulating a tdb database */
41
42 #define FSTRING_LEN 256
43 typedef char fstring[FSTRING_LEN];
44
45 typedef struct connections_key {
46         pid_t pid;
47         int cnum;
48         fstring name;
49 } connections_key;
50
51 typedef struct connections_data {
52         int magic;
53         pid_t pid;
54         int cnum;
55         uid_t uid;
56         gid_t gid;
57         char name[24];
58         char addr[24];
59         char machine[128];
60         time_t start;
61 } connections_data;
62
63 static struct tdb_context *tdb;
64
65 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
66
67 static void print_asc(unsigned char *buf,int len)
68 {
69         int i;
70
71         /* We're probably printing ASCII strings so don't try to display
72            the trailing NULL character. */
73
74         if (buf[len - 1] == 0)
75                 len--;
76
77         for (i=0;i<len;i++)
78                 printf("%c",isprint(buf[i])?buf[i]:'.');
79 }
80
81 #ifdef PRINTF_ATTRIBUTE
82 static void tdb_log(struct tdb_context *t, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
83 #endif
84 static void tdb_log(struct tdb_context *t, enum tdb_debug_level level, const char *format, ...)
85 {
86         va_list ap;
87     
88         va_start(ap, format);
89         vfprintf(stdout, format, ap);
90         va_end(ap);
91         fflush(stdout);
92 }
93
94 static void print_data(unsigned char *buf,int len)
95 {
96         int i=0;
97         if (len<=0) return;
98         printf("[%03X] ",i);
99         for (i=0;i<len;) {
100                 printf("%02X ",(int)buf[i]);
101                 i++;
102                 if (i%8 == 0) printf(" ");
103                 if (i%16 == 0) {      
104                         print_asc(&buf[i-16],8); printf(" ");
105                         print_asc(&buf[i-8],8); printf("\n");
106                         if (i<len) printf("[%03X] ",i);
107                 }
108         }
109         if (i%16) {
110                 int n;
111                 
112                 n = 16 - (i%16);
113                 printf(" ");
114                 if (n>8) printf(" ");
115                 while (n--) printf("   ");
116                 
117                 n = i%16;
118                 if (n > 8) n = 8;
119                 print_asc(&buf[i-(i%16)],n); printf(" ");
120                 n = (i%16) - n;
121                 if (n>0) print_asc(&buf[i-n],n); 
122                 printf("\n");    
123         }
124 }
125
126 static void help(void)
127 {
128         printf("\n"
129 "tdbtool: \n"
130 "  create    dbname     : create a database\n"
131 "  open      dbname     : open an existing database\n"
132 "  erase                : erase the database\n"
133 "  dump                 : dump the database as strings\n"
134 "  insert    key  data  : insert a record\n"
135 "  move      key  file  : move a record to a destination tdb\n"
136 "  store     key  data  : store a record (replace)\n"
137 "  show      key        : show a record by key\n"
138 "  delete    key        : delete a record by key\n"
139 "  list                 : print the database hash table and freelist\n"
140 "  free                 : print the database freelist\n"
141 "  1 | first            : print the first record\n"
142 "  n | next             : print the next record\n"
143 "  q | quit             : terminate\n"
144 "  \\n                   : repeat 'next' command\n"
145 "\n");
146 }
147
148 static void terror(const char *why)
149 {
150         printf("%s\n", why);
151 }
152
153 static char *get_token(int startover)
154 {
155         static char tmp[1024];
156         static char *cont = NULL;
157         char *insert, *start;
158         char *k = strtok(NULL, " ");
159
160         if (!k)
161           return NULL;
162
163         if (startover)
164           start = tmp;
165         else
166           start = cont;
167
168         strcpy(start, k);
169         insert = start + strlen(start) - 1;
170         while (*insert == '\\') {
171           *insert++ = ' ';
172           k = strtok(NULL, " ");
173           if (!k)
174             break;
175           strcpy(insert, k);
176           insert = start + strlen(start) - 1;
177         }
178
179         /* Get ready for next call */
180         cont = start + strlen(start) + 1;
181         return start;
182 }
183
184 static void create_tdb(void)
185 {
186         char *tok = get_token(1);
187         if (!tok) {
188                 help();
189                 return;
190         }
191         if (tdb) tdb_close(tdb);
192         tdb = tdb_open_ex(tok, 0, TDB_CLEAR_IF_FIRST,
193                           O_RDWR | O_CREAT | O_TRUNC, 0600, tdb_log, NULL, NULL);
194         if (!tdb) {
195                 printf("Could not create %s: %s\n", tok, strerror(errno));
196         }
197 }
198
199 static void open_tdb(void)
200 {
201         char *tok = get_token(1);
202         if (!tok) {
203                 help();
204                 return;
205         }
206         if (tdb) tdb_close(tdb);
207         tdb = tdb_open_ex(tok, 0, 0, O_RDWR, 0600, tdb_log, NULL, NULL);
208         if (!tdb) {
209                 printf("Could not open %s: %s\n", tok, strerror(errno));
210         }
211 }
212
213 static void insert_tdb(void)
214 {
215         char *k = get_token(1);
216         char *d = get_token(0);
217         TDB_DATA key, dbuf;
218
219         if (!k || !d) {
220                 help();
221                 return;
222         }
223
224         key.dptr = (unsigned char *)k;
225         key.dsize = strlen(k)+1;
226         dbuf.dptr = (unsigned char *)d;
227         dbuf.dsize = strlen(d)+1;
228
229         if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
230                 terror("insert failed");
231         }
232 }
233
234 static void store_tdb(void)
235 {
236         char *k = get_token(1);
237         char *d = get_token(0);
238         TDB_DATA key, dbuf;
239
240         if (!k || !d) {
241                 help();
242                 return;
243         }
244
245         key.dptr = (unsigned char *)k;
246         key.dsize = strlen(k)+1;
247         dbuf.dptr = (unsigned char *)d;
248         dbuf.dsize = strlen(d)+1;
249
250         printf("Storing key:\n");
251         print_rec(tdb, key, dbuf, NULL);
252
253         if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
254                 terror("store failed");
255         }
256 }
257
258 static void show_tdb(void)
259 {
260         char *k = get_token(1);
261         TDB_DATA key, dbuf;
262
263         if (!k) {
264                 help();
265                 return;
266         }
267
268         key.dptr = (unsigned char *)k;
269         key.dsize = strlen(k)+1;
270
271         dbuf = tdb_fetch(tdb, key);
272         if (!dbuf.dptr) {
273                 /* maybe it is non-NULL terminated key? */
274                 key.dsize = strlen(k); 
275                 dbuf = tdb_fetch(tdb, key);
276                 
277                 if ( !dbuf.dptr ) {
278                         terror("fetch failed");
279                         return;
280                 }
281         }
282         
283         /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
284         print_rec(tdb, key, dbuf, NULL);
285         
286         free( dbuf.dptr );
287         
288         return;
289 }
290
291 static void delete_tdb(void)
292 {
293         char *k = get_token(1);
294         TDB_DATA key;
295
296         if (!k) {
297                 help();
298                 return;
299         }
300
301         key.dptr = (unsigned char *)k;
302         key.dsize = strlen(k)+1;
303
304         if (tdb_delete(tdb, key) != 0) {
305                 terror("delete failed");
306         }
307 }
308
309 static void move_rec(void)
310 {
311         char *k = get_token(1);
312         char *file = get_token(0);      
313         TDB_DATA key, dbuf;
314         struct tdb_context *dst_tdb;
315
316         if (!k) {
317                 help();
318                 return;
319         }
320         
321         if ( !file ) {
322                 terror("need destination tdb name");
323                 return;
324         }
325
326         key.dptr = (unsigned char *)k;
327         key.dsize = strlen(k)+1;
328
329         dbuf = tdb_fetch(tdb, key);
330         if (!dbuf.dptr) {
331                 /* maybe it is non-NULL terminated key? */
332                 key.dsize = strlen(k); 
333                 dbuf = tdb_fetch(tdb, key);
334                 
335                 if ( !dbuf.dptr ) {
336                         terror("fetch failed");
337                         return;
338                 }
339         }
340         
341         print_rec(tdb, key, dbuf, NULL);
342         
343         dst_tdb = tdb_open_ex(file, 0, 0, O_RDWR, 0600, tdb_log, NULL, NULL);
344         if ( !dst_tdb ) {
345                 terror("unable to open destination tdb");
346                 return;
347         }
348         
349         if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
350                 terror("failed to move record");
351         }
352         else
353                 printf("record moved\n");
354         
355         tdb_close( dst_tdb );
356         
357         return;
358 }
359
360 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
361 {
362         printf("\nkey %d bytes\n", key.dsize);
363         print_asc(key.dptr, key.dsize);
364         printf("\ndata %d bytes\n", dbuf.dsize);
365         print_data(dbuf.dptr, dbuf.dsize);
366         return 0;
367 }
368
369 static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
370 {
371         print_asc(key.dptr, key.dsize);
372         printf("\n");
373         return 0;
374 }
375
376 static int total_bytes;
377
378 static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
379 {
380         total_bytes += dbuf.dsize;
381         return 0;
382 }
383
384 static void info_tdb(void)
385 {
386         int count;
387         total_bytes = 0;
388         if ((count = tdb_traverse(tdb, traverse_fn, NULL) == -1))
389                 printf("Error = %s\n", tdb_errorstr(tdb));
390         else
391                 printf("%d records totalling %d bytes\n", count, total_bytes);
392 }
393
394 static char *tdb_getline(const char *prompt)
395 {
396         static char line[1024];
397         char *p;
398         fputs(prompt, stdout);
399         line[0] = 0;
400         p = fgets(line, sizeof(line)-1, stdin);
401         if (p) p = strchr(p, '\n');
402         if (p) *p = 0;
403         return p?line:NULL;
404 }
405
406 static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
407                      void *state)
408 {
409     return tdb_delete(the_tdb, key);
410 }
411
412 static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
413 {
414         TDB_DATA dbuf;
415         *pkey = tdb_firstkey(the_tdb);
416         
417         dbuf = tdb_fetch(the_tdb, *pkey);
418         if (!dbuf.dptr) terror("fetch failed");
419         else {
420                 /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
421                 print_rec(the_tdb, *pkey, dbuf, NULL);
422         }
423 }
424
425 static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
426 {
427         TDB_DATA dbuf;
428         *pkey = tdb_nextkey(the_tdb, *pkey);
429         
430         dbuf = tdb_fetch(the_tdb, *pkey);
431         if (!dbuf.dptr) 
432                 terror("fetch failed");
433         else
434                 /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
435                 print_rec(the_tdb, *pkey, dbuf, NULL);
436 }
437
438 int main(int argc, char *argv[])
439 {
440     int bIterate = 0;
441     char *line;
442     char *tok;
443         TDB_DATA iterate_kbuf;
444
445     if (argv[1]) {
446         static char tmp[1024];
447         sprintf(tmp, "open %s", argv[1]);
448         tok=strtok(tmp," ");
449         open_tdb();
450     }
451
452     while ((line = tdb_getline("tdb> "))) {
453
454         /* Shell command */
455         
456         if (line[0] == '!') {
457             system(line + 1);
458             continue;
459         }
460         
461         if ((tok = strtok(line," "))==NULL) {
462            if (bIterate)
463               next_record(tdb, &iterate_kbuf);
464            continue;
465         }
466         if (strcmp(tok,"create") == 0) {
467             bIterate = 0;
468             create_tdb();
469             continue;
470         } else if (strcmp(tok,"open") == 0) {
471             open_tdb();
472             continue;
473         } else if ((strcmp(tok, "q") == 0) ||
474                    (strcmp(tok, "quit") == 0)) {
475             break;
476         }
477             
478         /* all the rest require a open database */
479         if (!tdb) {
480             bIterate = 0;
481             terror("database not open");
482             help();
483             continue;
484         }
485             
486         if (strcmp(tok,"insert") == 0) {
487             bIterate = 0;
488             insert_tdb();
489         } else if (strcmp(tok,"store") == 0) {
490             bIterate = 0;
491             store_tdb();
492         } else if (strcmp(tok,"show") == 0) {
493             bIterate = 0;
494             show_tdb();
495         } else if (strcmp(tok,"erase") == 0) {
496             bIterate = 0;
497             tdb_traverse(tdb, do_delete_fn, NULL);
498         } else if (strcmp(tok,"delete") == 0) {
499             bIterate = 0;
500             delete_tdb();
501         } else if (strcmp(tok,"dump") == 0) {
502             bIterate = 0;
503             tdb_traverse(tdb, print_rec, NULL);
504         } else if (strcmp(tok,"move") == 0) {
505             bIterate = 0;
506             move_rec();
507         } else if (strcmp(tok,"list") == 0) {
508             tdb_dump_all(tdb);
509         } else if (strcmp(tok, "free") == 0) {
510             tdb_printfreelist(tdb);
511         } else if (strcmp(tok,"info") == 0) {
512             info_tdb();
513         } else if ( (strcmp(tok, "1") == 0) ||
514                     (strcmp(tok, "first") == 0)) {
515             bIterate = 1;
516             first_record(tdb, &iterate_kbuf);
517         } else if ((strcmp(tok, "n") == 0) ||
518                    (strcmp(tok, "next") == 0)) {
519             next_record(tdb, &iterate_kbuf);
520         } else if ((strcmp(tok, "keys") == 0)) {
521                 bIterate = 0;
522                 tdb_traverse(tdb, print_key, NULL);
523         } else {
524             help();
525         }
526     }
527
528     if (tdb) tdb_close(tdb);
529
530     return 0;
531 }