diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-10-17 22:27:16 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-10-17 22:27:16 +0300 |
commit | 803128db75e3efea8cd7be29732a7b4315205d13 (patch) | |
tree | 713699a3724f905ca3dd740c386c9ffdb75e94a7 /src/binlogsel.c | |
parent | aad0ead6ae1bb56953642eac584d9a5f1dc6d72e (diff) | |
download | vmod-binlog-803128db75e3efea8cd7be29732a7b4315205d13.tar.gz vmod-binlog-803128db75e3efea8cd7be29732a7b4315205d13.tar.bz2 |
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.
Diffstat (limited to 'src/binlogsel.c')
-rw-r--r-- | src/binlogsel.c | 202 |
1 files changed, 183 insertions, 19 deletions
diff --git a/src/binlogsel.c b/src/binlogsel.c index 5238215..10630e6 100644 --- a/src/binlogsel.c +++ b/src/binlogsel.c @@ -25,12 +25,13 @@ #include <stdlib.h> #include <stdarg.h> #include <errno.h> #include <time.h> #include <string.h> #include <glob.h> +#include <ltdl.h> #include "vmod-binlog.h" #include "pack.h" #include "err.h" #include "xalloc.h" #include "parse-datetime.h" @@ -39,12 +40,20 @@ int number_option; int verbose_option; int timediff_option; 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 */ /* The two flags below are valid only for global timemask. They are set when building interval list and are then used in main to reset the START_TIME and STOP_TIME bits. */ @@ -93,28 +102,71 @@ interval_add(const char *name, int tmask, time_t start, time_t end) to_time = end; } else 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"); 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); @@ -205,12 +257,13 @@ selmem(const char *name, void *base) char *p; size_t i, start; time_t start_ts; char timebuf[128]; char *format; struct interval *ip; + size_t datasize; hdr = base; if (memcmp(hdr->magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN)) { error("%s is not a binlog file", name); return; @@ -225,26 +278,32 @@ selmem(const char *name, void *base) if (verbose_option) printf("# %s; format=%s; recsize=%lu; recnum=%lu\n", 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) { error("%s: %s: bad format near %s", name, format, p); return; } error("%s", strerror(errno)); return; } - env = packenv_create(hdr->recsize - - offsetof(struct binlog_record,data)); + env = packenv_create(datasize); env->fp = stdout; base = (char*)base + hdr->hdrsize; if (timemask & START_TIME) { switch (searchts(base, hdr->recsize, 0, hdr->recnum - 1, @@ -283,24 +342,31 @@ selmem(const char *name, void *base) memcpy(env->buf_base, rec->data, env->buf_size); for (ip = interval_head; ip; ip = ip->next) { if ((ip->timemask & START_TIME) && ip->start > rec->ts) 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 fchecktime(FILE *fp, const char *fname, time_t *ts) { struct binlog_file_header header; @@ -676,23 +742,97 @@ selglob(const char *dir, const char *pattern) selfile(logfiles[i].name); free(logfiles); 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) { int c; struct timespec ts; 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; break; case 'd': timediff_option = 1; @@ -719,12 +859,29 @@ main(int argc, char **argv) index_type = atoi(optarg); if (index_type < 0 || index_type > index_last) { error("invalid index type: %s", optarg); 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; case 'T': if (!parse_datetime(&ts, optarg, NULL)) { error("invalid timespec: %s", optarg); @@ -749,19 +906,24 @@ main(int argc, char **argv) exit(1); } 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) { error("either files or pattern (-p) must be given, " "but not both"); exit(1); @@ -769,9 +931,11 @@ main(int argc, char **argv) selfilelist(argv); } else if (pattern) { selglob(directory, convpattern(pattern)); } else { selidx_year(directory); } + if (module_done) + module_done(); exit(0); } |