From 803128db75e3efea8cd7be29732a7b4315205d13 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 17 Oct 2013 22:27:16 +0300 Subject: binlogsel: add loadable module support * Makefile.am (SUBDIRS): Add libltdl * configure.ac: Configure ltdl * src/Makefile.am (binlogsel_LDADD): Add LIBLTDL. (binlogsel_CPPFLAGS): New variable. * src/binlogcat.c (catlog): Bugfix. * src/binlogsel.c: Allow for multiple intervals. Support loadable modules. * doc/binlogcat.1: Update. * doc/binlogsel.1: Update. * doc/vmod-binlog.3: Update. --- src/binlogsel.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 183 insertions(+), 19 deletions(-) (limited to 'src/binlogsel.c') diff --git a/src/binlogsel.c b/src/binlogsel.c index 5238215..10630e6 100644 --- a/src/binlogsel.c +++ b/src/binlogsel.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "vmod-binlog.h" #include "pack.h" #include "err.h" @@ -42,6 +43,14 @@ char *directory; char *pattern; enum binlog_index_type index_type = index_year; +char *module_name; +char *module_args; +void (*module_init)(char *, void (*)(const char *, const char *, const char *)); +int (*module_open)(const char *, size_t, const char *); +void (*module_close)(void); +void (*module_done)(void); +void (*module_record)(const char *, time_t, void *); + /* Time mask flags indicate which timestamp is set. */ #define START_TIME 0x01 /* start time is set */ #define STOP_TIME 0x02 /* stop time is set */ @@ -95,23 +104,66 @@ interval_add(const char *name, int tmask, time_t start, time_t end) timemask |= CLEAR_STOP_TIME; } +void +interval_add_str(const char *id, const char *from, const char *to) +{ + struct timespec ts; + time_t start, end; + int tmask = 0; + + if (from) { + if (!parse_datetime(&ts, from, NULL)) { + error("invalid timespec: %s", from); + exit(1); + } + start = ts.tv_sec; + tmask |= START_TIME; + } + + if (to) { + if (!parse_datetime(&ts, to, NULL)) { + error("invalid timespec: %s", to); + exit(1); + } + end = ts.tv_sec; + tmask |= STOP_TIME; + } + + if (tmask) + interval_add(id, tmask, start, end); +} + + void help() { - printf("usage: %s [-dhnVv] [-t FORMAT] [-F TIME] [-T TIME] [-p PATTERN] [-D DIR] [-i 0|1|2] [FILE...]\n", progname); + printf("usage: %s [OPTIONS] [FILE...]\n", progname); printf("Select records from binary logs\n"); - printf("\nOptions are:\n\n"); + printf("\nOPTIONS are:\n\n"); + printf("File selection:\n"); printf(" -D DIR log file storage directory\n"); printf(" -i 0|1|2 select directory indexing level\n"); + printf(" -p PATTERN select files matching PATTERN\n"); + printf("\n"); + printf("Time intervals:\n"); + printf(" -I TAG set tag for the subsequent -F and -T option pair\n"); printf(" -F TIME print records starting from TIME\n"); printf(" -T TIME print records starting up to TIME\n"); - printf(" -p PATTERN select files matching PATTERN\n"); printf("\n"); + printf("Loadable module control\n"); + printf(" -L DIR append DIR to the loadable module search path\n"); + printf(" -P DIR add DIR to the loadable module search path before\n"); + printf(" the default module directory\n"); + printf(" -m 'MODULE[ ARGS]'\n"); + printf(" load given MODULE\n"); + printf("\n"); + printf("Output control:\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 FMT format timestamps according to FMT\n"); printf("\n"); + printf("Informational options:\n"); printf(" -h print this help summary\n"); printf(" -V show program version\n"); printf("\n"); @@ -208,6 +260,7 @@ selmem(const char *name, void *base) char timebuf[128]; char *format; struct interval *ip; + size_t datasize; hdr = base; @@ -228,6 +281,13 @@ selmem(const char *name, void *base) name, format, (unsigned long) hdr->recsize, (unsigned long) hdr->recnum); + datasize = hdr->recsize - offsetof(struct binlog_record,data); + + if (module_open && module_open(name, datasize, format)) { + error("%s: rejected by module %s", name, module_name); + return; + } + inst = packcomp(format, &p); if (!inst) { if (errno == EINVAL) { @@ -240,8 +300,7 @@ selmem(const char *name, void *base) return; } - env = packenv_create(hdr->recsize - - offsetof(struct binlog_record,data)); + env = packenv_create(datasize); env->fp = stdout; base = (char*)base + hdr->hdrsize; @@ -286,18 +345,25 @@ selmem(const char *name, void *base) continue; if ((ip->timemask & STOP_TIME) && ip->end < rec->ts) continue; - if (ip->name) - printf("%s ", ip->name); - else if (ip == interval_head && ip->next) - printf("default "); - if (number_option) - printf("%lu ", (unsigned long) start); - printf("%s ", timebuf); - env->buf_pos = 0; - packout(inst, env); - fputc('\n', stdout); + if (module_record) + module_record(ip->name, rec->ts, env->buf_base); + else { + if (ip->name) + printf("%s ", ip->name); + else if (ip == interval_head && ip->next) + printf("default "); + if (number_option) + printf("%lu ", (unsigned long) start); + printf("%s ", timebuf); + env->buf_pos = 0; + packout(inst, env); + fputc('\n', stdout); + } } } + + if (module_close) + module_close(); } static int @@ -679,6 +745,78 @@ selglob(const char *dir, const char *pattern) globfree(&gl); } +#define LP_PREPEND 0 +#define LP_APPEND 1 + +struct libdir { + struct libdir *next; + struct libdir *prev; + const char *dir; +}; + +struct libdir *libdir_head, *libdir_mid, *libdir_tail; + +void +add_load_path(const char *dir, int where) +{ + struct libdir *ld = xmalloc(sizeof(ld[0])); + ld->dir = dir; + if (!libdir_mid) { + ld->next = ld->prev = NULL; + libdir_mid = libdir_head = libdir_tail = ld; + } else if (where == LP_PREPEND) { + ld->next = libdir_mid; + ld->prev = libdir_mid->prev; + if (ld->prev) + ld->prev->next = libdir_mid; + else + libdir_head = ld; + libdir_mid->prev = ld; + } else /* if (where == LT_APPEND) */ { + ld->next = NULL; + ld->prev = libdir_tail; + libdir_tail->next = ld; + libdir_tail = ld; + } +} + +void +loader_init(void) +{ + struct libdir *ld; + lt_dlhandle handle = NULL; + lt_dladvise advise = NULL; + + if (!module_name) + return; + + lt_dlinit(); + for (ld = libdir_head; ld; ld = ld->next) + lt_dladdsearchdir(ld->dir); + + if (!lt_dladvise_init(&advise) && !lt_dladvise_ext(&advise) + && !lt_dladvise_global(&advise)) + handle = lt_dlopenadvise(module_name, advise); + lt_dladvise_destroy(&advise); + + if (!handle) { + error("cannot load module %s: %s", module_name, + lt_dlerror()); + exit(1); + } + + module_record = lt_dlsym(handle, "record"); + if (!module_record) { + error("%s: faulty module: function record() not defined", + module_name); + exit(1); + } + module_init = lt_dlsym(handle, "init"); + module_open = lt_dlsym(handle, "open"); + module_close = lt_dlsym(handle, "close"); + module_done = lt_dlsym(handle, "done"); +} + int main(int argc, char **argv) { @@ -687,9 +825,11 @@ main(int argc, char **argv) const char *id; int tmask = 0; time_t start, stop; + char *p; setprogname(argv[0]); - while ((c = getopt(argc, argv, "D:dF:hi:I:p:T:t:nV")) != EOF) + add_load_path(BINLOGSEL_MODDIR, LP_APPEND); + while ((c = getopt(argc, argv, "D:dF:hi:I:L:m:p:P:T:t:nV")) != EOF) switch (c) { case 'D': directory = optarg; @@ -722,6 +862,23 @@ main(int argc, char **argv) exit(1); } break; + case 'L': + add_load_path(optarg, LP_APPEND); + break; + case 'm': + p = strchr(optarg, ' '); + if (p) { + *p++ = 0; + while (*p == ' ') + p++; + if (*p) + module_args = p; + } + module_name = optarg; + break; + case 'P': + add_load_path(optarg, LP_PREPEND); + break; case 'p': pattern = optarg; break; @@ -752,13 +909,18 @@ main(int argc, char **argv) if (tmask) interval_add(id, tmask, start, stop); + argc -= optind; + argv += optind; + + loader_init(); + + if (module_init) + module_init(module_args, interval_add_str); + if (timemask & CLEAR_START_TIME) timemask &= ~START_TIME; if (timemask & CLEAR_STOP_TIME) timemask &= ~STOP_TIME; - - argc -= optind; - argv += optind; if (argc) { if (pattern) { @@ -772,6 +934,8 @@ main(int argc, char **argv) } else { selidx_year(directory); } + if (module_done) + module_done(); exit(0); } -- cgit v1.2.1