/* This file is part of vmod-binlog
Copyright (C) 2013-2014 Sergey Poznyakoff
Vmod-binlog is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Vmod-binlog is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with vmod-binlog. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "vmod-binlog.h"
#include "pack.h"
#include "err.h"
#include "xalloc.h"
char *timefmt = "%c";
int number_option;
int verbose_option;
int timediff_option;
void
catlog(const char *fname)
{
FILE *fp;
struct binlog_file_header header;
struct binlog_record *rec;
char timebuf[128];
size_t i;
time_t start_ts;
char *format;
size_t size;
struct packenv *env;
struct packinst *inst;
char *p;
if (strcmp(fname, "-") == 0)
fp = stdin;
else {
fp = fopen(fname, "r");
if (!fp) {
error("cannot open %s: %s", fname, strerror(errno));
exit(1);
}
}
if (fread(&header, sizeof(header), 1, fp) != 1) {
error("error reading header of %s: %s",
fname, strerror(errno));
exit(1);
}
if (memcmp(header.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN)) {
error("%s is not a binlog file", fname);
exit(1);
}
if (header.version != BINLOG_VERSION) {
error("%s: unknown version", fname);
exit(1);
}
size = header.hdrsize - sizeof(header);
format = xmalloc(size);
if (fread(format, size, 1, fp) != 1) {
error("error reading header of %s: %s",
fname, strerror(errno));
exit(1);
}
if (verbose_option)
printf("# %s; format=%s; recsize=%lu; recnum=%lu\n",
fname, format, (unsigned long) header.recsize,
(unsigned long) header.recnum);
inst = packcomp(format, &p);
if (!inst) {
if (errno == EINVAL) {
error("%s: %s: bad format near %s", fname, format, p);
exit(1);
}
error("%s", strerror(errno));
exit(1);
}
free(format);
rec = xmalloc(header.recsize);
env = packenv_create(header.recsize -
offsetof(struct binlog_record,data));
env->fp = stdout;
for (i = 0; i < header.recnum; i++) {
if (fread(rec, header.recsize, 1, fp) != 1) {
error("%s: unexpected eof", fname);
break;
}
if (timediff_option) {
if (i == 0)
start_ts = rec->ts;
rec->ts -= start_ts;
}
strftime(timebuf, sizeof timebuf, timefmt,
localtime(&rec->ts));
if (number_option)
printf("%lu ", (unsigned long) i);
printf("%s ", timebuf);
memcpy(env->buf_base, rec->data, env->buf_size);
env->buf_pos = 0;
packout(inst, env);
fputc('\n', stdout);
}
free(rec);
packenv_free(env);
packfree(inst);
fclose(fp);
}
void
help()
{
printf("usage: %s [-dhnVv] [-t FORMAT] [FILE...]\n", progname);
printf("Format binary log files in human-readable form\n");
printf("\nOptions are:\n\n");
printf(" -d print timestamps relative to first record in the file\n");
printf(" -n output record numbers\n");
printf(" -v print information about each file\n");
printf(" -t FORMAT format timestamps according to FORMAT\n");
printf("\n");
printf(" -h print this help summary\n");
printf(" -V show program version\n");
printf("\n");
printf("Report bugs and suggestions to <%s>\n", PACKAGE_BUGREPORT);
if (sizeof(PACKAGE_URL) > 1)
printf("%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL);
}
int
main(int argc, char **argv)
{
int c;
setprogname(argv[0]);
while ((c = getopt(argc, argv, "dht:nVv")) != EOF)
switch (c) {
case 'd':
timediff_option = 1;
timefmt = "%s";
break;
case 'h':
help();
return 0;
case 't':
timefmt = optarg;
break;
case 'n':
number_option = 1;
break;
case 'V':
version();
exit(0);
case 'v':
verbose_option = 1;
break;
default:
exit(1);
}
argc -= optind;
argv += optind;
if (argc == 0)
catlog("-");
else while (argc--)
catlog(*(argv++));
return 0;
}