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