/* This file is part of vmod-binlog Copyright (C) 2013 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 *dataspec; 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", 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); dataspec = xmalloc(size); if (fread(dataspec, 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, dataspec, header.recsize, header.recnum); inst = packcomp(dataspec, &p); if (!inst) { if (errno == EINVAL) { error("%s: %s: bad dataspec near %s", fname, dataspec, p); exit(1); } error("%s", strerror(errno)); exit(1); } free(dataspec); 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 [-dhnv] [-t FORMAT] [FILE...]\n", progname); } int main(int argc, char **argv) { int c; setprogname(argv[0]); while ((c = getopt(argc, argv, "dht:nv")) != 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': verbose_option = 1; break; default: exit(1); } argc -= optind; argv += optind; if (argc == 0) catlog("-"); else while (argc--) catlog(*(argv++)); return 0; }