aboutsummaryrefslogtreecommitdiff
path: root/src/binlogsel.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-10-17 22:27:16 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2013-10-17 22:27:16 +0300
commit803128db75e3efea8cd7be29732a7b4315205d13 (patch)
tree713699a3724f905ca3dd740c386c9ffdb75e94a7 /src/binlogsel.c
parentaad0ead6ae1bb56953642eac584d9a5f1dc6d72e (diff)
downloadvmod-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.c202
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);
}

Return to:

Send suggestions and report system problems to the System administrator.