KlugyTools/DumpGDBM/dumpgdbm.c

809 lines
15 KiB
C

/*
dumpgdbm.c
==========
Very old Homepage = http://tboudet.free.fr/dumpgdbm/
(g) 2003 Thierry Boudet - aka TontonTh
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <gdbm.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <regex.h>
#define MAIN 1
#include "dumpgdbm.h"
/* --------------------------------------------------------------------- */
/* global variables */
int warn_if_key_empty = 0;
int found_an_empty_key = 0;
int interactive = 0;
int leading_zero = 1;
#define MAX_FILENAME_LENGTH 4242 /* 63 bytes for a filename is enough
for all. -imaginary BG- */
char filename[MAX_FILENAME_LENGTH+2];
/* --------------------------------------------------------------------- */
static void
dump_entry(datum key, datum data, int maxsize)
{
#if TRACE
printf("@,L: %p,%d %p,%d\n", key.dptr, key.dsize, data.dptr, data.dsize);
#endif
printf("K: ");
if (hexadecimal) hexadump(key.dptr, key.dsize);
else if (octal) octaldump(key.dptr, key.dsize);
else asciidump(key.dptr, key.dsize);
printf("D: ");
if (hexadecimal) hexadump(data.dptr, data.dsize);
else if (octal) octaldump(data.dptr, data.dsize);
else asciidump(data.dptr, data.dsize);
free(data.dptr); /* XXX XXX */
printf("\n");
}
/* --------------------------------------------------------------------- */
/*
* here we have the main loop for batches dumps.
*/
static int
dump_gdbm_file(char *name)
{
GDBM_FILE file;
datum entry, datas;
file = gdbm_open(name, 512, GDBM_READER, 0444, NULL);
#if TRACE
fprintf(stderr, "retour gdbm_open = %08lx\n", (unsigned long)file);
#endif
if (file == NULL)
{
fprintf(stderr, "can't open %s\n", name);
return -1;
}
entry = gdbm_firstkey(file);
if (entry.dptr == NULL)
{
fprintf(stderr, "database %s is empty\n", name);
exit(2);
}
do
{
datas = gdbm_fetch(file, entry);
if (entry.dsize == 0)
{
found_an_empty_key = 1;
}
dump_entry(entry, datas, maxoctets);
/*
* XXX may be we must free the data memory here ?
*/
entry = gdbm_nextkey(file, entry);
} while ( entry.dptr != NULL);
gdbm_close(file);
return 0;
}
/* --------------------------------------------------------------------- */
/*
* Oct 17 2002: use of regular expressions.
*/
int search_key(GDBM_FILE gf, char * pattern)
{
datum entry, datas;
char *bufptr, *cptr;
int foo;
regex_t reg;
regmatch_t match[1];
if (pattern == NULL)
{
fprintf(stderr, "no pattern ??\n");
return -1;
}
foo = strlen(pattern);
if (pattern[foo-1] == '\n')
pattern[foo-1] = '\0';
#if TRACE
fprintf(stderr, "Search Key: cleaned pattern [%s]\n", pattern);
#endif
foo = regcomp(&reg, pattern, REG_EXTENDED);
#if TRACE
printf("regcomp ---> %d\n", foo);
#endif
entry = gdbm_firstkey(gf);
if (entry.dptr == NULL)
{
fprintf(stderr, "database is empty or bugged\n");
exit(2);
}
do
{
bufptr = (char *)malloc(entry.dsize+2);
if (bufptr == NULL)
{
fprintf(stderr, "in Search Key: no memory, sorry\n");
exit(5);
}
strncpy(bufptr, entry.dptr, entry.dsize);
bufptr[entry.dsize] = '\0';
#if TRACE
fprintf(stderr, "Search Key: bufptr is [%s]\n", bufptr);
#endif
foo = regexec(&reg, bufptr, 1, match, 0);
if (foo==0)
{
datas = gdbm_fetch(gf, entry);
dump_entry(entry, datas, maxoctets);
}
free(bufptr); /* 26 Jul 2002 */
entry = gdbm_nextkey(gf, entry);
} while ( entry.dptr != NULL);
regfree(&reg);
return 0;
}
/* --------------------------------------------------------------------- */
/*
* Oct 16 2002: use of regular expressions.
*/
int search_data(GDBM_FILE gf, char * pattern)
{
datum entry, datas;
char *bufptr;
int foo;
regex_t reg;
regmatch_t match[1];
if (pattern == NULL)
{
fprintf(stderr, "no pattern ??\n");
return -1;
}
foo = strlen(pattern);
if (pattern[foo-1] == '\n')
pattern[foo-1] = '\0';
#if TRACE
fprintf(stderr, "\nSearch Data: cleaned pattern [%s]\n", pattern);
#endif
foo = regcomp(&reg, pattern, REG_EXTENDED);
#if TRACE
printf("regcomp ---> %d\n", foo);
#endif
entry = gdbm_firstkey(gf);
if (entry.dptr == NULL)
{
fprintf(stderr, "database is empty or bugged\n");
exit(2);
}
do
{
datas = gdbm_fetch(gf, entry);
if (datas.dsize > 0)
{
bufptr = (char *)malloc(datas.dsize+2);
if (bufptr == NULL)
{
fprintf(stderr, "in Search Data: no memory, sorry\n");
exit(5);
}
strncpy(bufptr, datas.dptr, datas.dsize);
bufptr[datas.dsize] = '\0';
#if TRACE
// fprintf(stderr, "Search Data: bufptr [%s]\n", bufptr);
#endif
foo = regexec(&reg, bufptr, 1, match, 0);
if (foo==0)
{
dump_entry(entry, datas, maxoctets);
}
}
else
{
fprintf(stderr, "data size is 0 ?\n");
}
entry = gdbm_nextkey(gf, entry);
} while ( entry.dptr != NULL);
regfree(&reg);
return 0;
}
/* --------------------------------------------------------------------- */
#define CMDLINE_LENGTH 80
#define CMD_QUIT 1
#define CMD_HEX 2
#define CMD_ASCII 3
#define CMD_OCTAL 4
#define CMD_FIRST 5
#define CMD_NEXT 6
#define CMD_SEVEN 7
#define CMD_HEIGHT 8
#define CMD_PRINT 10
#define CMD_KEYSEARCH 12
#define CMD_DATASEARCH 13
#define CMD_MAXOCT 14
#define CMD_FMBL 15
#define CMD_EMPTY 16
#define CMD_HELP 42
#define CMD_LISTCOM 43
#define CMD_VERSION 51
typedef struct
{
char *keyw;
int code;
} Commande;
Commande commandes[] =
{
{ "q", CMD_QUIT },
{ "ZZ", CMD_QUIT },
{ ":q", CMD_QUIT },
{ ":q!", CMD_QUIT },
{ "exit", CMD_QUIT },
{ "quit", CMD_QUIT },
{ "bye", CMD_QUIT },
{ "x", CMD_HEX },
{ "hex", CMD_HEX },
{ "hexa", CMD_HEX },
{ "a", CMD_ASCII },
{ "ascii", CMD_ASCII },
{ "o", CMD_OCTAL },
{ "octal", CMD_OCTAL },
{ "h", CMD_HELP },
{ "help", CMD_HELP },
{ "?", CMD_HELP },
{ "f", CMD_FIRST },
{ "first", CMD_FIRST },
{ "m", CMD_MAXOCT },
{ "maxoctets", CMD_MAXOCT },
{ "maxbytes", CMD_MAXOCT },
{ "n", CMD_NEXT },
{ "next", CMD_NEXT },
{ "p", CMD_PRINT },
{ "print", CMD_PRINT },
{ "ks", CMD_KEYSEARCH },
{ "keysearch", CMD_KEYSEARCH },
{ "ds", CMD_DATASEARCH },
{ "datasearch", CMD_DATASEARCH },
{ "empty", CMD_EMPTY },
{ "7", CMD_SEVEN },
{ "8", CMD_HEIGHT },
{ "V", CMD_VERSION },
{ "version", CMD_VERSION },
{ "commands", CMD_LISTCOM },
{ "listcom", CMD_LISTCOM },
{ "sux", 0 }
};
#define NBRE_CMD (sizeof(commandes)/sizeof(Commande))
typedef struct
{
int number;
char *text;
} Help;
char Help_version[] =
"If you send me a bug report at <oulala@chez.com>, you must give me\n"
" this information, with the output of 'uname -a' command.";
char Help_maxoctet[] =
"change the number of bytes displayed for key & data field.\n"
" can be modified with the -m NN command line option.";
char Help_print[] =
"re-print the current record, so you can see it with different 'base':\n"
" ascii, hexadecimal or octal. use '? [a|x|o]' for more info.";
char Help_first[] =
"JUMPTO the first record. you have to understand this. man gdbm.";
char Help_next[] =
"GOTO the next record. you have to understand this. 'man gdbm' is a must.";
char Help_seven[] =
"only true ASCII chars are printed. others are displayed as '.'";
char Help_height[] =
"display all chars. beware of differences in charset between Os !";
char Help_KS[] = "Search a posix regex pattern in all the key fields.";
char Help_DS[] = "POSIX extended regex search in all the data fields.";
char No_Help_Text[] = "this help text need to be written...";
Help help[] =
{
{ 0, "just a joke for my friend tnemeth :)" },
{ CMD_QUIT, "good bye, cruel world." },
{ CMD_VERSION, Help_version },
{ CMD_HEX, "switch to hexadecimal display." },
{ CMD_OCTAL, "switch to octal display, you own a pdp11 ???" },
{ CMD_ASCII, "switch to ascii display, see 7 & 8 commands." },
{ CMD_MAXOCT, Help_maxoctet },
{ CMD_PRINT, Help_print },
{ CMD_FIRST, Help_first },
{ CMD_NEXT, Help_next },
{ CMD_SEVEN, Help_seven },
{ CMD_HEIGHT, Help_height },
{ CMD_KEYSEARCH, Help_KS },
{ CMD_DATASEARCH, Help_DS },
{ CMD_HELP, "sure, 42 is the ultimate answer !" }
};
#define NBRE_HELP (sizeof(help)/sizeof(Help))
// -------------------------
static int
lookup_cmd(char *cmd)
{
int foo;
/*
* bon, la, c'est un hack un peu crade... mais je pense
* que c'est qu'on rec,oit un parametre foireux...
*/
if ( cmd[strlen(cmd)-1] == '\n') cmd[strlen(cmd)-1] = '\0';
#if TRACE
printf("lookup cmd [%s]\n", cmd);
#endif
for (foo=0; foo<NBRE_CMD; foo++)
{
#if TRACE
// printf("try cmd #%d %s\n", foo, commandes[foo].keyw);
#endif
if ( ! strcmp(commandes[foo].keyw, cmd) )
return commandes[foo].code;
}
return -1;
}
// -------------------------
static void
help_cli(void)
{
int foo, bar;
printf("----------------( Help me Obi Wan ! )---------------\n");
for (foo=bar=0; foo<NBRE_CMD; foo++)
{
bar += printf("%s ", commandes[foo].keyw);
if (bar > 69) /* sex number ? */
{
bar = 0; puts("");
}
}
printf("\n-----------( use '? command' for details )----------\n");
}
static void
full_help(char *keyword)
{
int num_keyword, foo;
num_keyword = lookup_cmd(keyword);
#if TRACE
fprintf(stderr, "%s -> %d\n", keyword, num_keyword);
#endif
if (num_keyword == -1)
{
printf("%s: no such command\n", keyword);
return;
}
for (foo=0; foo<NBRE_HELP; foo++)
{
#if TRACE
fprintf(stderr, "%4d %4d %s\n", foo, help[foo].number, help[foo].text);
#endif
if (help[foo].number == num_keyword)
{
printf("\ncommand [%s]\n %s\n\n", keyword, help[foo].text);
}
}
}
static int list_commands(int foo)
{
puts("q ZZ exit : quit Dumpgdbm.");
puts("x hex : hexadecimal display");
puts("a ascii : ascii display");
puts("o octal : octal display");
// puts("h help | help");
puts("f first : jump to first record");
puts("n next : next record");
puts("m maxbytes : set number of displayed bytes");
puts("p print : redisplay the current record");
puts("ks : key search");
puts("ds | data search");
return 0;
}
// -------------------------
// Interpreteur de commandes
// -------------------------
static void
shell(void)
{
char *cptr, *pline;
int code_cmd, flag_exit, value;
GDBM_FILE gdbm_file;
datum entry, datas;
int first_ok = 0;
flag_exit = 0; // on va pas s'arreter maintenant ?
printf("working on [%s]\n", filename);
gdbm_file = gdbm_open(filename, 512, GDBM_READER, 0444, NULL);
if (gdbm_file == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return;
}
/*
* init of readline behaviour
*/
rl_bind_key('\t', rl_insert); /* no filename completion, silly here :) */
do
{
pline = readline("dumpgdbm > ");
if (pline == NULL)
{
printf("\nEOF ?\n");
break;
}
/*
* if the line is not empty, add it to the history
*/
if ( pline && *pline )
add_history(pline);
#if TRACE
printf("[%s]\n", pligne);
#endif
/*
* search the first token on the line
*/
cptr = strtok(pline, " \t");
#if TRACE
fprintf(stderr, "pline %p cptr %p\n", pline, cptr);
#endif
/*
* is there a text on this command-line ?
*/
if ( cptr==NULL || !strcmp("\n", cptr) ) continue;
#if TRACE
printf("token = %s\n", cptr);
#endif
/*
* Ok, la commande est pointee par cptr, on va tenter
* de la comprendre...
*/
code_cmd = lookup_cmd(cptr);
switch (code_cmd)
{
case CMD_QUIT: flag_exit = 1; break;
case CMD_HEX:
hexadecimal = 1;
octal = 0;
break;
case CMD_OCTAL:
octal = 1;
hexadecimal = 0;
break;
case CMD_ASCII:
octal = hexadecimal = 0;
break;
case CMD_HELP:
cptr = strtok(NULL, " \t");
if (cptr == NULL || *cptr == '\0')
help_cli();
else
full_help(cptr);
break;
case CMD_VERSION: print_version(1); break;
case CMD_FIRST:
entry = gdbm_firstkey(gdbm_file);
if (entry.dptr == NULL)
{
fprintf(stderr, "database is empty\n");
break;
}
datas = gdbm_fetch(gdbm_file, entry);
dump_entry(entry, datas, maxoctets);
first_ok = 1;
break;
case CMD_NEXT:
if (first_ok)
entry = gdbm_nextkey(gdbm_file, entry);
else
entry = gdbm_firstkey(gdbm_file);
first_ok = 1;
if (entry.dptr == NULL)
{
fprintf(stderr, "end of database\n");
break;
}
datas = gdbm_fetch(gdbm_file, entry);
dump_entry(entry, datas, maxoctets);
break;
case CMD_PRINT:
if ( ! first_ok )
entry = gdbm_firstkey(gdbm_file);
first_ok = 42;
if (entry.dptr == NULL)
{
fprintf(stderr, "Print: no entry\n");
break;
}
datas = gdbm_fetch(gdbm_file, entry);
dump_entry(entry, datas, maxoctets);
break;
case CMD_KEYSEARCH:
cptr = strtok(NULL, " \t");
if (cptr != NULL)
{
search_key(gdbm_file, cptr);
}
else
{
fprintf(stderr, "keysearch need an argument\n");
}
break;
case CMD_DATASEARCH:
#if TRACE
fprintf(stderr, "==== DATA SEARCH ====\n");
#endif
search_data(gdbm_file, strtok(NULL, " \t"));
break;
case CMD_MAXOCT:
cptr = strtok(NULL, " \t");
if (cptr != NULL)
{
#if TRACE
fprintf(stderr, "MAXOCT: cptr %s\n", cptr);
#endif
if ( sscanf(cptr, "%d", &value) == 1 )
{
printf("maxoctets = %d\n", value);
maxoctets = value;
}
}
else
{
fprintf(stderr, "need a numeric argument\n");
}
break;
case CMD_SEVEN:
ok_for_8_bits = 0;
break;
case CMD_HEIGHT:
ok_for_8_bits = 1;
break;
case CMD_LISTCOM:
list_commands(0);
break;
case 0:
fprintf(stderr, "\t\tChimera roulaize grave a donf\n");
fprintf(stderr, "\t\tAthena widgets are so nice !!\n");
break;
default:
fprintf(stderr, "command %s : huho ?\n", cptr);
break;
}
#if TRACE
fprintf(stderr, "freeing command line %p\n", pline);
#endif
free(pline);
} while ( ! flag_exit );
}
/* --------------------------------------------------------------------- */
static char *optstring = "VvxohwW8m:ia";
int main(int argc, char *argv[])
{
int option_retour;
int foo;
init_global_vars();
while ( (option_retour = getopt(argc, argv, optstring)) >= 0)
{
#if TRACE
fprintf(stderr, "getopt = %d, argc = %d, optind = %d\n",
option_retour, argc, optind);
#endif
switch (option_retour)
{
case 'V':
print_version(1);
exit(1);
break;
case 'v':
verbosity++;
if (verbosity > 5)
{
fprintf(stderr, "Higher verbosity !\n");
fprintf(stderr, "now dumping kernel...\n");
sleep(5);
exit(1);
}
break;
case 'a':
hexadecimal = octal = 0;
break;
case 'x':
hexadecimal = 1;
octal = 0;
break;
case 'o':
octal = 1;
hexadecimal = 0;
break;
case 'h':
print_version(0);
print_options();
exit(2);
break;
case 'w':
warn_if_key_empty = 1;
break;
case '8':
ok_for_8_bits = 1;
break;
case 'i':
interactive = 1;
break;
case 'm':
if (sscanf(optarg, "%d", &foo) == 1)
{
maxoctets = foo;
}
else
{
fprintf(stderr,"opt 'm' need a numeric arg\n");
exit(5);
}
break;
}
}
#if TRACE
fprintf(stderr, "fin traitement options argc=%d, optind=%d\n",
argc, optind);
#endif
/*
* a cet endroit il est probable qu'on puisse memoriser
* le nom du fichier GDBM dans une variable globale.
*/
if (optind != argc)
{
strncpy(filename, argv[optind], MAX_FILENAME_LENGTH);
}
else
{
fprintf(stderr, "WARNING: dumpgdbm: missing filename\n");
print_options();
exit(1);
}
if (interactive)
{
shell();
}
else
{
dump_gdbm_file(argv[optind]);
}
if (found_an_empty_key && warn_if_key_empty)
{
fprintf(stderr, "YO! A KEY IS EMPTY\n");
}
return 0;
}
/* ------------------------------------------------------- the end ----- */