Browse Source

introduce driver call debugging

do that by wrapping the actual stores into proxies.

the proxy driver's code is auto-generated from function templates, some
parameters, and the declarations of the driver functions themselves.
attempts to do it with CPP macros turned out to be a nightmare.
wip/movedetect
Oswald Buddenhagen 8 years ago
parent
commit
4cc5ad5a1a
  1. 1
      src/.gitignore
  2. 10
      src/Makefile.am
  3. 4
      src/common.h
  4. 11
      src/driver.h
  5. 1
      src/drv_imap.c
  6. 1
      src/drv_maildir.c
  7. 335
      src/drv_proxy.c
  8. 169
      src/drv_proxy_gen.pl
  9. 29
      src/main.c
  10. 8
      src/mbsync.1
  11. 17
      src/sync.c

1
src/.gitignore vendored

@ -1,3 +1,4 @@
/drv_proxy.inc
/mbsync /mbsync
/mdconvert /mdconvert
/tst_timers /tst_timers

10
src/Makefile.am

@ -3,10 +3,14 @@ compat_dir = compat
endif endif
SUBDIRS = $(compat_dir) SUBDIRS = $(compat_dir)
mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c drv_proxy.c
mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS) mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS)
noinst_HEADERS = common.h config.h driver.h sync.h socket.h noinst_HEADERS = common.h config.h driver.h sync.h socket.h
drv_proxy.$(OBJEXT): drv_proxy.inc
drv_proxy.inc: $(srcdir)/driver.h $(srcdir)/drv_proxy.c $(srcdir)/drv_proxy_gen.pl
perl $(srcdir)/drv_proxy_gen.pl $(srcdir)/driver.h $(srcdir)/drv_proxy.c drv_proxy.inc
mdconvert_SOURCES = mdconvert.c mdconvert_SOURCES = mdconvert.c
mdconvert_LDADD = $(DB_LIBS) mdconvert_LDADD = $(DB_LIBS)
if with_mdconvert if with_mdconvert
@ -24,4 +28,6 @@ man_MANS = mbsync.1 $(mdconvert_man)
exampledir = $(docdir)/examples exampledir = $(docdir)/examples
example_DATA = mbsyncrc.sample example_DATA = mbsyncrc.sample
EXTRA_DIST = run-tests.pl $(example_DATA) $(man_MANS) EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS)
CLEANFILES = drv_proxy.inc

4
src/common.h

@ -70,7 +70,9 @@ typedef unsigned int uint;
#define DEBUG_NET_ALL 0x08 #define DEBUG_NET_ALL 0x08
#define DEBUG_SYNC 0x10 #define DEBUG_SYNC 0x10
#define DEBUG_MAIN 0x20 #define DEBUG_MAIN 0x20
#define DEBUG_ALL (0xFF & ~DEBUG_NET_ALL) #define DEBUG_DRV 0x40
#define DEBUG_DRV_ALL 0x80
#define DEBUG_ALL (0xFF & ~(DEBUG_NET_ALL | DEBUG_DRV_ALL))
#define QUIET 0x100 #define QUIET 0x100
#define VERYQUIET 0x200 #define VERYQUIET 0x200
#define PROGRESS 0x400 #define PROGRESS 0x400

11
src/driver.h

@ -87,6 +87,7 @@ typedef struct message {
typedef struct store { typedef struct store {
struct store *next; struct store *next;
driver_t *driver;
store_conf_t *conf; /* foreign */ store_conf_t *conf; /* foreign */
} store_t; } store_t;
@ -124,9 +125,11 @@ typedef struct {
#define LIST_PATH 2 #define LIST_PATH 2
#define LIST_PATH_MAYBE 4 #define LIST_PATH_MAYBE 4
#define xint int // For auto-generation of appropriate printf() formats.
struct driver { struct driver {
/* Return driver capabilities. */ /* Return driver capabilities. */
int (*get_caps)( store_t *ctx ); xint (*get_caps)( store_t *ctx );
/* Parse configuration. */ /* Parse configuration. */
int (*parse_store)( conffile_t *cfg, store_conf_t **storep ); int (*parse_store)( conffile_t *cfg, store_conf_t **storep );
@ -192,7 +195,7 @@ struct driver {
/* Invoked before load_box(), this informs the driver which operations (OP_*) /* Invoked before load_box(), this informs the driver which operations (OP_*)
* will be performed on the mailbox. The driver may extend the set by implicitly * will be performed on the mailbox. The driver may extend the set by implicitly
* needed or available operations. Returns this possibly extended set. */ * needed or available operations. Returns this possibly extended set. */
int (*prepare_load_box)( store_t *ctx, int opts ); xint (*prepare_load_box)( store_t *ctx, xint opts );
/* Load the message attributes needed to perform the requested operations. /* Load the message attributes needed to perform the requested operations.
* Consider only messages with UIDs between minuid and maxuid (inclusive) * Consider only messages with UIDs between minuid and maxuid (inclusive)
@ -260,8 +263,10 @@ void free_generic_messages( message_t * );
void parse_generic_store( store_conf_t *store, conffile_t *cfg ); void parse_generic_store( store_conf_t *store, conffile_t *cfg );
store_t *proxy_alloc_store( store_t *real_ctx, const char *label );
#define N_DRIVERS 2 #define N_DRIVERS 2
extern driver_t *drivers[N_DRIVERS]; extern driver_t *drivers[N_DRIVERS];
extern driver_t maildir_driver, imap_driver; extern driver_t maildir_driver, imap_driver, proxy_driver;
#endif #endif

1
src/drv_imap.c

@ -1708,6 +1708,7 @@ imap_alloc_store( store_conf_t *conf, const char *label )
ctx->pending_append = &ctx->pending; ctx->pending_append = &ctx->pending;
gotsrv: gotsrv:
ctx->gen.driver = &imap_driver;
ctx->gen.conf = conf; ctx->gen.conf = conf;
ctx->label = label; ctx->label = label;
ctx->ref_count = 1; ctx->ref_count = 1;

1
src/drv_maildir.c

@ -226,6 +226,7 @@ maildir_alloc_store( store_conf_t *gconf, const char *label ATTR_UNUSED )
maildir_store_t *ctx; maildir_store_t *ctx;
ctx = nfcalloc( sizeof(*ctx) ); ctx = nfcalloc( sizeof(*ctx) );
ctx->gen.driver = &maildir_driver;
ctx->gen.conf = gconf; ctx->gen.conf = gconf;
ctx->uvfd = -1; ctx->uvfd = -1;
init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx ); init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx );

335
src/drv_proxy.c

@ -0,0 +1,335 @@
/*
* mbsync - mailbox synchronizer
* Copyright (C) 2017 Oswald Buddenhagen <ossi@users.sf.net>
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, mbsync may be linked with the OpenSSL library,
* despite that library's more restrictive license.
*/
#include "driver.h"
#include <limits.h>
#include <stdlib.h>
typedef struct {
store_t gen;
const char *label; // foreign
int ref_count;
driver_t *real_driver;
store_t *real_store;
void (*bad_callback)( void *aux );
void *bad_callback_aux;
} proxy_store_t;
static void ATTR_PRINTFLIKE(1, 2)
debug( const char *msg, ... )
{
va_list va;
va_start( va, msg );
vdebug( DEBUG_DRV, msg, va );
va_end( va );
}
static void ATTR_PRINTFLIKE(1, 2)
debugn( const char *msg, ... )
{
va_list va;
va_start( va, msg );
vdebugn( DEBUG_DRV, msg, va );
va_end( va );
}
static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
static char *
proxy_make_flags( int flags, char *buf )
{
uint i, d;
for (d = 0, i = 0; i < as(Flags); i++)
if (flags & (1 << i))
buf[d++] = Flags[i];
buf[d] = 0;
return buf;
}
static void
proxy_store_deref( proxy_store_t *ctx )
{
if (!--ctx->ref_count)
free( ctx );
}
static int curr_tag;
typedef struct {
int ref_count;
int tag;
proxy_store_t *ctx;
} gen_cmd_t;
static gen_cmd_t *
proxy_cmd_new( proxy_store_t *ctx, int sz )
{
gen_cmd_t *cmd = nfmalloc( sz );
cmd->ref_count = 2;
cmd->tag = ++curr_tag;
cmd->ctx = ctx;
ctx->ref_count++;
return cmd;
}
static void
proxy_cmd_done( gen_cmd_t *cmd )
{
if (!--cmd->ref_count) {
proxy_store_deref( cmd->ctx );
free( cmd );
}
}
#if 0
//# TEMPLATE GETTER
static @type@proxy_@name@( store_t *gctx )
{
proxy_store_t *ctx = (proxy_store_t *)gctx;
@type@rv = ctx->real_driver->@name@( ctx->real_store );
debug( "%sCalled @name@, ret=@fmt@\n", ctx->label, rv );
return rv;
}
//# END
//# TEMPLATE REGULAR
static @type@proxy_@name@( store_t *gctx@decl_args@ )
{
proxy_store_t *ctx = (proxy_store_t *)gctx;
@pre_print_args@
debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ );
@print_args@
@type@rv = ctx->real_driver->@name@( ctx->real_store@pass_args@ );
debug( "%sLeave @name@, ret=@fmt@\n", ctx->label, rv );
return rv;
}
//# END
//# TEMPLATE REGULAR_VOID
static void proxy_@name@( store_t *gctx@decl_args@ )
{
proxy_store_t *ctx = (proxy_store_t *)gctx;
@pre_print_args@
debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ );
@print_args@
ctx->real_driver->@name@( ctx->real_store@pass_args@ );
debug( "%sLeave @name@\n", ctx->label );
@action@
}
//# END
//# TEMPLATE CALLBACK
typedef struct {
gen_cmd_t gen;
void (*callback)( @decl_cb_args@void *aux );
void *callback_aux;
@decl_state@
} @name@_cmd_t;
static void
proxy_@name@_cb( @decl_cb_args@void *aux )
{
@name@_cmd_t *cmd = (@name@_cmd_t *)aux;
@pre_print_cb_args@
debug( "%s[% 2d] Callback enter @name@@print_fmt_cb_args@\n", cmd->gen.ctx->label, cmd->gen.tag@print_pass_cb_args@ );
@print_cb_args@
cmd->callback( @pass_cb_args@cmd->callback_aux );
debug( "%s[% 2d] Callback leave @name@\n", cmd->gen.ctx->label, cmd->gen.tag );
proxy_cmd_done( &cmd->gen );
}
static void
proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@void *aux ), void *aux )
{
proxy_store_t *ctx = (proxy_store_t *)gctx;
@name@_cmd_t *cmd = (@name@_cmd_t *)proxy_cmd_new( ctx, sizeof(@name@_cmd_t) );
cmd->callback = cb;
cmd->callback_aux = aux;
@assign_state@
@pre_print_args@
debug( "%s[% 2d] Enter @name@@print_fmt_args@\n", ctx->label, cmd->gen.tag@print_pass_args@ );
@print_args@
ctx->real_driver->@name@( ctx->real_store@pass_args@, proxy_@name@_cb, cmd );
debug( "%s[% 2d] Leave @name@\n", ctx->label, cmd->gen.tag );
proxy_cmd_done( &cmd->gen );
}
//# END
//# UNDEFINE list_store_print_fmt_cb_args
//# UNDEFINE list_store_print_pass_cb_args
//# DEFINE list_store_print_cb_args
if (sts == DRV_OK) {
for (string_list_t *box = boxes; box; box = box->next)
debug( " %s\n", box->string );
}
//# END
//# DEFINE load_box_pre_print_args
static char ubuf[12];
//# END
//# DEFINE load_box_print_fmt_args , [%d,%s] (new >= %d, seen <= %d)
//# DEFINE load_box_print_pass_args , minuid, (maxuid == INT_MAX) ? "inf" : (nfsnprintf( ubuf, sizeof(ubuf), "%d", maxuid ), ubuf), newuid, seenuid
//# DEFINE load_box_print_args
if (excs.size) {
debugn( " excs:" );
for (int t = 0; t < excs.size; t++)
debugn( " %d", excs.data[t] );
debug( "\n" );
}
//# END
//# DEFINE load_box_pre_print_cb_args
static char fbuf[as(Flags) + 1];
//# END
//# DEFINE load_box_print_fmt_cb_args , sts=%d, total=%d, recent=%d
//# DEFINE load_box_print_pass_cb_args , sts, total_msgs, recent_msgs
//# DEFINE load_box_print_cb_args
if (sts == DRV_OK) {
for (message_t *msg = msgs; msg; msg = msg->next)
debug( " uid=%5d, flags=%4s, size=%6d, tuid=%." stringify(TUIDL) "s\n",
msg->uid, (msg->status & M_FLAGS) ? (proxy_make_flags( msg->flags, fbuf ), fbuf) : "?", msg->size, *msg->tuid ? msg->tuid : "?" );
}
//# END
//# DEFINE find_new_msgs_print_fmt_cb_args , sts=%d
//# DEFINE find_new_msgs_print_pass_cb_args , sts
//# DEFINE find_new_msgs_print_cb_args
if (sts == DRV_OK) {
for (message_t *msg = msgs; msg; msg = msg->next)
debug( " uid=%5d, tuid=%." stringify(TUIDL) "s\n", msg->uid, msg->tuid );
}
//# END
//# DEFINE fetch_msg_decl_state
msg_data_t *data;
//# END
//# DEFINE fetch_msg_assign_state
cmd->data = data;
//# END
//# DEFINE fetch_msg_print_fmt_args , uid=%d, want_flags=%s, want_date=%s
//# DEFINE fetch_msg_print_pass_args , msg->uid, !(msg->status & M_FLAGS) ? "yes" : "no", data->date ? "yes" : "no"
//# DEFINE fetch_msg_pre_print_cb_args
static char fbuf[as(Flags) + 1];
proxy_make_flags( cmd->data->flags, fbuf );
//# END
//# DEFINE fetch_msg_print_fmt_cb_args , flags=%s, date=%ld, size=%d
//# DEFINE fetch_msg_print_pass_cb_args , fbuf, cmd->data->date, cmd->data->len
//# DEFINE fetch_msg_print_cb_args
if (sts == DRV_OK && (DFlags & DEBUG_DRV_ALL)) {
printf( "%s=========\n", cmd->gen.ctx->label );
fwrite( cmd->data->data, cmd->data->len, 1, stdout );
printf( "%s=========\n", cmd->gen.ctx->label );
fflush( stdout );
}
//# END
//# DEFINE store_msg_pre_print_args
static char fbuf[as(Flags) + 1];
proxy_make_flags( data->flags, fbuf );
//# END
//# DEFINE store_msg_print_fmt_args , flags=%s, date=%ld, size=%d, to_trash=%s
//# DEFINE store_msg_print_pass_args , fbuf, data->date, data->len, to_trash ? "yes" : "no"
//# DEFINE store_msg_print_args
if (DFlags & DEBUG_DRV_ALL) {
printf( "%s>>>>>>>>>\n", ctx->label );
fwrite( data->data, data->len, 1, stdout );
printf( "%s>>>>>>>>>\n", ctx->label );
fflush( stdout );
}
//# END
//# DEFINE set_msg_flags_pre_print_args
static char fbuf1[as(Flags) + 1], fbuf2[as(Flags) + 1];
proxy_make_flags( add, fbuf1 );
proxy_make_flags( del, fbuf2 );
//# END
//# DEFINE set_msg_flags_print_fmt_args , uid=%d, add=%s, del=%s
//# DEFINE set_msg_flags_print_pass_args , uid, fbuf1, fbuf2
//# DEFINE trash_msg_print_fmt_args , uid=%d
//# DEFINE trash_msg_print_pass_args , msg->uid
//# DEFINE free_store_action
proxy_store_deref( ctx );
//# END
//# DEFINE cancel_store_action
proxy_store_deref( ctx );
//# END
#endif
//# SPECIAL commit_cmds
static void
proxy_commit_cmds( store_t *gctx )
{
// Currently a dummy in all real drivers.
(void) gctx;
}
//# SPECIAL set_bad_callback
static void
proxy_set_bad_callback( store_t *gctx, void (*cb)( void *aux ), void *aux )
{
proxy_store_t *ctx = (proxy_store_t *)gctx;
ctx->bad_callback = cb;
ctx->bad_callback_aux = aux;
}
static void
proxy_invoke_bad_callback( proxy_store_t *ctx )
{
debug( "%sCallback enter bad store\n", ctx->label );
ctx->bad_callback( ctx->bad_callback_aux );
debug( "%sCallback leave bad store\n", ctx->label ); \
}
//# EXCLUDE alloc_store
store_t *
proxy_alloc_store( store_t *real_ctx, const char *label )
{
proxy_store_t *ctx;
ctx = nfcalloc( sizeof(*ctx) );
ctx->gen.driver = &proxy_driver;
ctx->gen.conf = real_ctx->conf;
ctx->ref_count = 1;
ctx->label = label;
ctx->real_driver = real_ctx->driver;
ctx->real_store = real_ctx;
ctx->real_driver->set_bad_callback( ctx->real_store, (void (*)(void *))proxy_invoke_bad_callback, ctx );
return &ctx->gen;
}
//# EXCLUDE parse_store
//# EXCLUDE cleanup
//# EXCLUDE get_fail_state
#include "drv_proxy.inc"

169
src/drv_proxy_gen.pl

@ -0,0 +1,169 @@
#!/usr/bin/perl
#
# mbsync - mailbox synchronizer
# Copyright (C) 2017 Oswald Buddenhagen <ossi@users.sf.net>
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, mbsync may be linked with the OpenSSL library,
# despite that library's more restrictive license.
#
use strict;
use warnings;
die("Usage: $0 driver.h drv_proxy.c drv_proxy.inc\n")
if ($#ARGV != 2);
my ($in_header, $in_source, $out_source) = @ARGV;
my %templates;
my %defines;
my %excluded;
my %special;
open(my $ins, $in_source) or die("Cannot open $in_source: $!\n");
my $template;
my $define;
my $conts;
while (<$ins>) {
if ($template) {
if (/^\/\/\# END$/) {
$templates{$template} = $conts;
$template = undef;
} else {
$conts .= $_;
}
} elsif ($define) {
if (/^\/\/\# END$/) {
$defines{$define} = $conts;
$define = undef;
} else {
$conts .= $_;
}
} else {
if (/^\/\/\# TEMPLATE (\w+)$/) {
$template = $1;
$conts = "";
} elsif (/^\/\/\# DEFINE (\w+)$/) {
$define = $1;
$conts = "";
} elsif (/^\/\/\# DEFINE (\w+) (.*)$/) {
$defines{$1} = $2;
} elsif (/^\/\/\# UNDEFINE (\w+)$/) {
$defines{$1} = "";
} elsif (/^\/\/\# EXCLUDE (\w+)$/) {
$excluded{$1} = 1;
} elsif (/^\/\/\# SPECIAL (\w+)$/) {
$special{$1} = 1;
}
}
}
close($ins);
open(my $inh, $in_header) or die("Cannot open $in_header: $!\n");
my $sts = 0;
my $cont = "";
while (<$inh>) {
if ($sts == 0) {
if (/^struct driver \{$/) {
$sts = 1;
}
} elsif ($sts == 1) {
if (/^\};$/) {
$sts = 0;
} else {
$cont .= $_;
}
}
}
close($inh);
$cont =~ s,\n, ,g;
$cont =~ s,/\*.*?\*/, ,g;
$cont =~ s,\h+, ,g;
my @ptypes = map { s,^ ,,r } split(/;/, $cont);
pop @ptypes; # last one is empty
my @cmd_table;
sub make_args($)
{
$_ = shift;
s/(?:^|(?<=, ))(?:const )?\w+ \*?//g;
return $_;
}
sub type_to_format($)
{
$_ = shift;
s/xint /\%\#x/g;
s/int /\%d/g;
s/const char \*/\%s/g;
return $_;
}
sub make_format($)
{
$_ = type_to_format(shift);
s/, (\%\#?.)(\w+)/, $2=$1/g;
return $_;
}
open(my $outh, ">".$out_source) or die("Cannot create $out_source: $!\n");
for (@ptypes) {
/^([\w* ]+)\(\*(\w+)\)\( (.*) \)$/ or die("Cannot parse prototype '$_'\n");
my ($cmd_type, $cmd_name, $cmd_args) = ($1, $2, $3);
if (defined($excluded{$cmd_name})) {
push @cmd_table, "0";
next;
}
push @cmd_table, "proxy_$cmd_name";
next if (defined($special{$cmd_name}));
my %replace;
$replace{'name'} = $cmd_name;
$replace{'type'} = $cmd_type;
$cmd_args =~ s/^store_t \*ctx// or die("Arguments '$cmd_args' don't start with 'store_t *ctx'\n");
if ($cmd_type eq "void " && $cmd_args =~ s/, void \(\*cb\)\( (.*)void \*aux \), void \*aux$//) {
my $cmd_cb_args = $1;
$replace{'decl_cb_args'} = $cmd_cb_args;
$replace{'pass_cb_args'} = make_args($cmd_cb_args);
my $cmd_print_cb_args = $cmd_cb_args =~ s/(.*), $/, $1/r;
$replace{'print_pass_cb_args'} = make_args($cmd_print_cb_args);
$replace{'print_fmt_cb_args'} = make_format($cmd_print_cb_args);
$template = "CALLBACK";
} elsif ($cmd_name =~ /^get_/) {
$template = "GETTER";
$replace{'fmt'} = type_to_format($cmd_type);
} elsif ($cmd_type eq "void ") {
$template = "REGULAR_VOID";
} else {
$template = "REGULAR";
$replace{'fmt'} = type_to_format($cmd_type);
}
$replace{'decl_args'} = $cmd_args;
$replace{'print_pass_args'} = $replace{'pass_args'} = make_args($cmd_args);
$replace{'print_fmt_args'} = make_format($cmd_args);
for (keys %defines) {
$replace{$1} = $defines{$_} if (/^${cmd_name}_(.*)$/);
}
my $text = $templates{$template};
$text =~ s/^\h*\@(\w+)\@\n/$replace{$1} \/\/ ""/smeg;
$text =~ s/\@(\w+)\@/$replace{$1} \/\/ ""/eg;
print $outh $text."\n";
}
print $outh "struct driver proxy_driver = {\n".join("", map { "\t$_,\n" } @cmd_table)."};\n";
close $outh;

29
src/main.c

@ -462,6 +462,10 @@ main( int argc, char **argv )
op = VERBOSE | DEBUG_ALL; op = VERBOSE | DEBUG_ALL;
else if (!strcmp( opt, "-crash" )) else if (!strcmp( opt, "-crash" ))
op = DEBUG_CRASH; op = DEBUG_CRASH;
else if (!strcmp( opt, "-driver" ))
op = VERBOSE | DEBUG_DRV;
else if (!strcmp( opt, "-driver-all" ))
op = VERBOSE | DEBUG_DRV | DEBUG_DRV_ALL;
else if (!strcmp( opt, "-maildir" )) else if (!strcmp( opt, "-maildir" ))
op = VERBOSE | DEBUG_MAILDIR; op = VERBOSE | DEBUG_MAILDIR;
else if (!strcmp( opt, "-main" )) else if (!strcmp( opt, "-main" ))
@ -648,6 +652,12 @@ main( int argc, char **argv )
case 'C': case 'C':
op |= DEBUG_CRASH; op |= DEBUG_CRASH;
break; break;
case 'd':
op |= DEBUG_DRV | VERBOSE;
break;
case 'D':
op |= DEBUG_DRV | DEBUG_DRV_ALL | VERBOSE;
break;
case 'm': case 'm':
op |= DEBUG_MAILDIR | VERBOSE; op |= DEBUG_MAILDIR | VERBOSE;
break; break;
@ -811,14 +821,20 @@ sync_chans( main_vars_t *mvars, int ent )
if (mvars->skip) if (mvars->skip)
goto next2; goto next2;
mvars->state[M] = mvars->state[S] = ST_FRESH; mvars->state[M] = mvars->state[S] = ST_FRESH;
if (mvars->chan->stores[M]->driver->get_caps( 0 ) & mvars->chan->stores[S]->driver->get_caps( 0 ) & DRV_VERBOSE) if ((DFlags & DEBUG_DRV) || (mvars->chan->stores[M]->driver->get_caps( 0 ) & mvars->chan->stores[S]->driver->get_caps( 0 ) & DRV_VERBOSE))
labels[M] = "M: ", labels[S] = "S: "; labels[M] = "M: ", labels[S] = "S: ";
else else
labels[M] = labels[S] = ""; labels[M] = labels[S] = "";
for (t = 0; t < 2; t++) { for (t = 0; t < 2; t++) {
mvars->drv[t] = mvars->chan->stores[t]->driver; driver_t *drv = mvars->chan->stores[t]->driver;
mvars->ctx[t] = mvars->drv[t]->alloc_store( mvars->chan->stores[t], labels[t] ); store_t *ctx = drv->alloc_store( mvars->chan->stores[t], labels[t] );
mvars->drv[t]->set_bad_callback( mvars->ctx[t], store_bad, AUX ); if (DFlags & DEBUG_DRV) {
drv = &proxy_driver;
ctx = proxy_alloc_store( ctx, labels[t] );
}
mvars->drv[t] = drv;
mvars->ctx[t] = ctx;
drv->set_bad_callback( ctx, store_bad, AUX );
} }
for (t = 0; ; t++) { for (t = 0; ; t++) {
info( "Opening %s store %s...\n", str_ms[t], mvars->chan->stores[t]->name ); info( "Opening %s store %s...\n", str_ms[t], mvars->chan->stores[t]->name );
@ -1008,11 +1024,6 @@ store_listed( int sts, string_list_t *boxes, void *aux )
case DRV_CANCELED: case DRV_CANCELED:
return; return;
case DRV_OK: case DRV_OK:
if (DFlags & DEBUG_MAIN) {
debug( "got mailbox list from %s:\n", str_ms[t] );
for (box = boxes; box; box = box->next)
debug( " %s\n", box->string );
}
for (box = boxes; box; box = box->next) { for (box = boxes; box; box = box->next) {
if (mvars->ctx[t]->conf->flat_delim) { if (mvars->ctx[t]->conf->flat_delim) {
string_list_t *nbox; string_list_t *nbox;

8
src/mbsync.1

@ -83,12 +83,16 @@ Display version information.
\fB-V\fR, \fB--verbose\fR \fB-V\fR, \fB--verbose\fR
Enable \fIverbose\fR mode, which displays what is currently happening. Enable \fIverbose\fR mode, which displays what is currently happening.
.TP .TP
\fB-D\fR[\fBC\fR][\fBm\fR][\fBM\fR][\fBn\fR|\fBN\fR][\fBs\fR]\fR]\fR,\ \fB-D\fR[\fBC\fR][\fBd\fR|\fBD\fR][\fBm\fR][\fBM\fR][\fBn\fR|\fBN\fR][\fBs\fR]\fR]\fR,\
\fB--debug\fR[\fB-crash\fR|\fB-maildir\fR|\fB-main\fR|\fB-net\fR|\fB-net-all\fR|\fB-sync\fR] \fB--debug\fR[\fB-crash\fR|\fB-driver\fR|\fB-driver-all\fR|\fB-maildir\fR|\fB-main\fR|\fB-net\fR|\fB-net-all\fR|\fB-sync\fR]
Enable debugging categories: Enable debugging categories:
.in +4 .in +4
\fBC\fR, \fBcrash\fR - use built-in crash handler \fBC\fR, \fBcrash\fR - use built-in crash handler
.br .br
\fBd\fR, \fBdriver\fR - print driver calls (metadata only)
.br
\fBD\fR, \fBdriver-all\fR - print driver calls (including messages)
.br
\fBm\fR, \fBmaildir\fR - print maildir debug info \fBm\fR, \fBmaildir\fR - print maildir debug info
.br .br
\fBM\fR, \fBmain\fR - print main debug info \fBM\fR, \fBmain\fR - print main debug info

17
src/sync.c

@ -1003,7 +1003,7 @@ sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *
sync_bail3( svars ); sync_bail3( svars );
return; return;
} }
svars->drv[t] = ctx[t]->conf->driver; svars->drv[t] = ctx[t]->driver;
svars->drv[t]->set_bad_callback( ctx[t], store_bad, AUX ); svars->drv[t]->set_bad_callback( ctx[t], store_bad, AUX );
} }
/* Both boxes must be fully set up at this point, so that error exit paths /* Both boxes must be fully set up at this point, so that error exit paths
@ -1284,10 +1284,6 @@ box_opened2( sync_vars_t *svars, int t )
} }
} }
sort_int_array( mexcs.array ); sort_int_array( mexcs.array );
debugn( " exception list is:" );
for (t = 0; t < mexcs.array.size; t++)
debugn( " %d", mexcs.array.data[t] );
debug( "\n" );
} else { } else {
minwuid = 1; minwuid = 1;
} }
@ -1336,10 +1332,6 @@ load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs )
seenuid = svars->maxuid[t]; seenuid = svars->maxuid[t];
} }
info( "Loading %s...\n", str_ms[t] ); info( "Loading %s...\n", str_ms[t] );
if (maxwuid == INT_MAX)
debug( "loading %s [%d,inf] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, svars->newuid[t], seenuid );
else
debug( "loading %s [%d,%d] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, maxwuid, svars->newuid[t], seenuid );
svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX ); svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX );
} }
@ -1372,7 +1364,6 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
int uid, no[2], del[2], alive, todel, t1, t2; int uid, no[2], del[2], alive, todel, t1, t2;
int sflags, nflags, aflags, dflags; int sflags, nflags, aflags, dflags;
uint hashsz, idx; uint hashsz, idx;
char fbuf[16]; /* enlarge when support for keywords is added */
if (check_ret( sts, aux )) if (check_ret( sts, aux ))
return; return;
@ -1406,10 +1397,6 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
if (tmsg->srec) /* found by TUID */ if (tmsg->srec) /* found by TUID */
continue; continue;
uid = tmsg->uid; uid = tmsg->uid;
if (DFlags & DEBUG_SYNC) {
make_flags( tmsg->flags, fbuf );
printf( tmsg->size ? " message %5d, %-4s, %6d: " : " message %5d, %-4s: ", uid, fbuf, tmsg->size );
}
idx = (uint)((uint)uid * 1103515245U) % hashsz; idx = (uint)((uint)uid * 1103515245U) % hashsz;
while (srecmap[idx].uid) { while (srecmap[idx].uid) {
if (srecmap[idx].uid == uid) { if (srecmap[idx].uid == uid) {
@ -1419,12 +1406,10 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
if (++idx == hashsz) if (++idx == hashsz)
idx = 0; idx = 0;
} }
debug( "new\n" );
continue; continue;
found: found:
tmsg->srec = srec; tmsg->srec = srec;
srec->msg[t] = tmsg; srec->msg[t] = tmsg;
debug( "pairs %5d\n", srec->uid[1-t] );
} }
free( srecmap ); free( srecmap );

Loading…
Cancel
Save