aboutsummaryrefslogtreecommitdiff
path: root/src/binlogsel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/binlogsel.c')
-rw-r--r--src/binlogsel.c245
1 files changed, 228 insertions, 17 deletions
diff --git a/src/binlogsel.c b/src/binlogsel.c
index 62299e5..8f1cfce 100644
--- a/src/binlogsel.c
+++ b/src/binlogsel.c
@@ -35,27 +35,32 @@
#include "parse-datetime.h"
char *timefmt = "%c";
int number_option;
int verbose_option;
int timediff_option;
+char *directory;
char *pattern;
+enum binlog_index_type index_type = index_year;
#define FROM_TIME 0x01
#define TO_TIME 0x02
int timemask;
time_t from_time, to_time;
+static int matchnames(const char *dir, const char *pat, glob_t *gl);
+void selglob(const char *dir, const char *pattern);
+
void
help()
{
printf("usage: %s [-dhnv] [-t FORMAT] [-F FROMTIME] [-T TOTIME] [-p PATTERN] [-D DIR] [FILE...]\n", progname);
}
-
+
/* Convert strftime-like pattern into globbing pattern */
-void
+char *
convpattern(const char *dir)
{
char *p, *q;
char *newpat;
size_t size = strlen(pattern) + 1;
@@ -70,19 +75,20 @@ convpattern(const char *dir)
p += strlen(dir);
*p++ = '/';
}
for (q = pattern; *q; ) {
if (*q == '%') {
- *p++ = '*';
+ if (p > newpat && p[-1] != '*')
+ *p++ = '*';
q += 2;
} else
*p++ = *q++;
}
*p = 0;
- pattern = newpat;
+ return newpat;
}
#define getrec(base, recsize, n) \
((struct binlog_record*)((char *)(base) + (n) * (recsize)))
int
@@ -329,20 +335,218 @@ selfile(char *name)
void
selfilelist(char **argv)
{
for (;*argv;++argv)
selfile(*argv);
}
+
+static char *
+mkfilename(const char *dir, const char *file)
+{
+ size_t dirlen, size;
+ char *ret;
+
+ dirlen = strlen(dir);
+ while (dirlen > 0 && dir[dirlen-1] == '/')
+ --dirlen;
+ size = dirlen + 1 + strlen(file) + 1;
+ ret = xmalloc(size);
+ memcpy(ret, dir, dirlen);
+ ret[dirlen++] = '/';
+ strcpy(ret + dirlen, file);
+ return ret;
+}
+
+int
+filename_to_int(char *name)
+{
+ char *p = strrchr(name, '/');
+ if (!p)
+ abort();
+ return atoi(p + 1);
+}
+
+void
+selidx_day(const char *dir)
+{
+ int from_day, to_day;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (index_type == index_month) {
+ selglob(dir, BINLOG_GLOB_PATTERN);
+ return;
+ }
+
+ if (timemask & FROM_TIME)
+ from_day = gmtime(&from_time)->tm_mday;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (glinit)
+ from_day = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+
+ if (timemask & TO_TIME)
+ to_day = gmtime(&to_time)->tm_mday;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_day = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 4;
+ dirbuf = xmalloc(dirlen);
+ for (;from_day <= to_day; from_day++) {
+ snprintf(dirbuf, dirlen, "%s/%02d", dir, from_day);
+ selglob(dirbuf, BINLOG_GLOB_PATTERN);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
+void
+selidx_month(const char *dir)
+{
+ int from_month, to_month;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (index_type == index_year) {
+ selglob(dir, BINLOG_GLOB_PATTERN);
+ return;
+ }
+
+ if (timemask & FROM_TIME)
+ from_month = 1 + gmtime(&from_time)->tm_mon;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (glinit)
+ from_month = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+
+ if (timemask & TO_TIME)
+ to_month = 1 + gmtime(&to_time)->tm_mon;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_month = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 4;
+ dirbuf = xmalloc(dirlen);
+ for (;from_month <= to_month; from_month++) {
+ snprintf(dirbuf, dirlen, "%s/%02d", dir, from_month);
+ selidx_day(dirbuf);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
+void
+selidx_year(const char *dir)
+{
+ int from_year, to_year;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (timemask & FROM_TIME)
+ from_year = 1900 + gmtime(&from_time)->tm_year;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9][0-9][0-9]", &gl);
+ if (glinit)
+ from_year = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ if (timemask & TO_TIME)
+ to_year = 1900 + gmtime(&to_time)->tm_year;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9][0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_year = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 6;
+ dirbuf = xmalloc(dirlen);
+ for (;from_year <= to_year; from_year++) {
+ snprintf(dirbuf, dirlen, "%s/%04d", dir, from_year);
+ selidx_month(dirbuf);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
int
globerrfunc (const char *epath, int eerrno)
{
- error("%s: %s", strerror(eerrno));
+ error("%s: %s", epath, strerror(eerrno));
return 0;
}
+static int
+matchnames(const char *dir, const char *pat, glob_t *gl)
+{
+ char *p = mkfilename(dir, pat);
+ int rc = glob(p, GLOB_ERR, globerrfunc, gl);
+ free(p);
+ switch (rc) {
+ case 0:
+ break;
+ case GLOB_NOSPACE:
+ error("out of memory");
+ exit(1);
+
+ case GLOB_ABORTED:
+ error("read error");
+ exit(1);
+
+ case GLOB_NOMATCH:
+ return 0;
+ }
+ return 1;
+}
+
+
struct logfile {
char *name;
time_t start;
};
static int
@@ -355,19 +559,20 @@ tsort(const void *a, const void *b)
if (la->start < lb->start)
return -1;
return 0;
}
void
-selpattern(void)
+selglob(const char *dir, const char *pattern)
{
size_t i, j;
glob_t gl;
struct logfile *logfiles;
-
- switch (glob(pattern, GLOB_ERR|GLOB_NOSORT, globerrfunc, &gl)) {
+ char *p = mkfilename(dir, pattern);
+
+ switch (glob(p, GLOB_ERR|GLOB_NOSORT, globerrfunc, &gl)) {
case 0:
break;
case GLOB_NOSPACE:
error("out of memory");
exit(1);
@@ -376,13 +581,14 @@ selpattern(void)
exit(1);
case GLOB_NOMATCH:
error("no files matched pattern");
exit(1);
}
-
+ free(p);
+
logfiles = xcalloc(gl.gl_pathc, sizeof(*logfiles));
for (i = j = 0; i < gl.gl_pathc; i++) {
time_t t;
if (checktime(gl.gl_pathv[i], &t) == 0) {
logfiles[j].name = gl.gl_pathv[i];
@@ -397,22 +603,21 @@ selpattern(void)
for (i = 0; i < j; i++)
selfile(logfiles[i].name);
free(logfiles);
globfree(&gl);
}
-
+
int
main(int argc, char **argv)
{
int c;
struct timespec ts;
- char *directory;
setprogname(argv[0]);
- while ((c = getopt(argc, argv, "D:dF:hp:T:t:nv")) != EOF)
+ while ((c = getopt(argc, argv, "D:dF:hi:p:T:t:nv")) != EOF)
switch (c) {
case 'D':
directory = optarg;
break;
case 'd':
timediff_option = 1;
@@ -426,12 +631,19 @@ main(int argc, char **argv)
from_time = ts.tv_sec;
timemask |= FROM_TIME;
break;
case 'h':
help();
return 0;
+ case 'i':
+ index_type = atoi(optarg);
+ if (index_type < 0 || index_type > index_last) {
+ error("invalid index type: %s", optarg);
+ exit(1);
+ }
+ break;
case 'p':
pattern = optarg;
break;
case 'T':
if (!parse_datetime(&ts, optarg, NULL)) {
error("invalid timespec: %s", optarg);
@@ -454,21 +666,20 @@ main(int argc, char **argv)
}
argc -= optind;
argv += optind;
if (argc) {
- if (pattern) {
+ if (pattern || directory) {
error("either files or pattern (-p) must be given, "
"but not both");
exit(1);
}
selfilelist(argv);
+ } else if (pattern) {
+ selglob(directory, convpattern(pattern));
} else {
- if (!pattern)
- pattern = BINLOG_PATTERN;
- convpattern(directory);
- selpattern();
+ selidx_year(directory);
}
exit(0);
}

Return to:

Send suggestions and report system problems to the System administrator.