/*
* Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_IDSTR(id, "@(#)$Id: t-idbrecover-2.c,v 1.28 2007/06/18 04:42:30 ca Exp $")
#define QMGR_DEBUG_DEFINE 1
#include "sm/io.h"
#include "sm/mta.h"
#include "sm/ibdb.h"
#include "sm/cdb.h"
#include "sm/qmgr.h"
#include "sm/memops.h"
#include "sm/bhtable.h"
#include "sm/test.h"
#include <stdio.h>
/*
** Test program to recover content of IBDB.
** Performs a recovery run using ibdbrcvr_open() from "../qmgr/rdibdb.c"
*/
static int debug = 0;
#define SM_TEST_PRT 1
/* context for *_action() calls (and probably others later on) */
typedef struct te_ctx_S te_ctx_T, *te_ctx_P;
struct te_ctx_S
{
bht_P tex_crt_bht;
bht_P tex_crt_bhr;
bht_P tex_rd_bht;
bht_P tex_rd_bhr;
uint tex_ntas;
uint tex_nrcpts;
};
/* HACK */
#include "../qmgr/rdibdb.c"
/* dummy function */
sm_ret_T
edb_reql_free(edb_ctx_P edb_ctx, edb_req_hd_P edb_req_hd)
{
return SM_SUCCESS;
}
#define FNAME "ibd"
#define IBDBSIZE 8192
#define INIT_SEQ 1
static int init_seq = INIT_SEQ;
static sm_ret_T
rdibdb(ri_ctx_P ri_ctx)
{
uint32_t first, last;
sm_ret_T ret, ibdb_which, res;
bool once;
ibdbr_ctx_P ibdbrc;
/* Initialize most variables */
ibdbrc = NULL;
ibdb_which = 0;
once = false;
ret = SM_SUCCESS;
again:
/* Prepare for recovery */
ibdb_which = ibdbrcvr_open();
QM_LEV_DPRINTF(4, (QM_DEBFP, "qm_rdibdb running; once=%d, ibdbrcvr_open=%x\n", once, ibdb_which));
if (sm_is_err(ibdb_which))
{
SM_TEST(ibdb_which == SM_SUCCESS);
goto end;
}
if (ibdb_which == SM_IBDB_NO_RCVR)
goto end;
ret = ibdbf_get_seq(NULL, IBDB_NAME, IBDB_OFL_RCVR, &first, &last);
QM_LEV_DPRINTF(4, (QM_DEBFP, "qm_rdibdb: ibdbf_get_seq=%#x, first=%u, last=%u\n", ret, first, last));
/* distinguish error values? e.g., no directory? */
if (sm_is_err(ret))
{
ret = SM_SUCCESS;
goto end; /* XXX no data? */
}
ret = ibdbr_open(NULL, IBDB_NAME, SM_IO_RDONLY, first, 0 /* unused */,
IBDB_OFL_RCVR, &ibdbrc);
if (ret != SM_SUCCESS)
goto end;
ri_ctx->rix_ibdbrc = ibdbrc;
ri_ctx->rix_time = time(NULLT);
/* Actually read IBDB */
ret = qm_ribdb(ri_ctx);
if (sm_is_err(ret))
goto end;
if (first <= last && ret == SM_SUCCESS)
{
res = ibdbr_unlink(ibdbrc, first, last);
QM_LEV_DPRINTF(2, (QM_DEBFP, "qm_rdibdb: ibdbr_unlink=%x\n", ret));
}
end:
if (ibdbrc != NULL)
{
ret = ibdbr_close(ibdbrc);
/* XXX Complain on error? */
ibdbrc = NULL;
}
res = ibdbrcvr_close(); /* check result? */
SM_TEST(res == SM_SUCCESS);
QM_LEV_DPRINTF(3, (QM_DEBFP, "qm_rdibdb: ibdbrcvr_close=%x\n", ret));
if (ibdb_which == SM_IBDB_RCVR_EXISTS)
{
if (once)
{
/* oops ... been there, done that? */
QM_LEV_DPRINTF(0, (QM_DEBFP, "ERROR: endless loop in qm_rdibdb\n"));
}
else
{
once = true;
goto again;
}
}
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "#TAs: %u\n", ri_ctx->rix_ntas);
sm_io_fprintf(smioout, "#RCPTs: %u\n", ri_ctx->rix_nrcpts);
sm_io_flush(smioout);
}
#endif /* SM_TEST_PRT */
return ret;
}
/*
** TA_ACTION -- Add transaction to DEFEDB (callback function)
**
** Parameters:
** info -- bht entry
** ctx -- context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
test_ta_action(bht_entry_P info, void *ctx)
{
sm_ret_T ret;
ibdb_ta_P ibdb_ta, ibdb_ta2;
te_ctx_P te_ctx;
te_ctx = (te_ctx_P) ctx;
ibdb_ta = (ibdb_ta_P) info->bhe_value;
if (ibdb_ta->ibt_ta_id == NULL)
return sm_err_perm(EINVAL);
++te_ctx->tex_ntas;
if (debug > 2)
sm_io_fprintf(smioout, "OPEN TA: ta=%s\n", info->bhe_key);
ibdb_ta2 = bht_find(te_ctx->tex_rd_bht, info->bhe_key, SMTP_STID_SIZE);
SM_TEST(ibdb_ta2 != NULL);
if (ibdb_ta2 == NULL)
{
/* OOPS what's going on? Where's our TA? */
sm_io_fprintf(smioout, "ERROR: bht_find(%s) failed\n", info->bhe_key);
return sm_err_perm(ENOENT);
}
#if 0
sm_io_fprintf(smioout, "OPEN TA: ta=%s, ", ibdb_ta->ibt_ta_id);
sm_io_fprintf(smioout, "cdb=%C, ", ibdb_ta->ibt_cdb_id);
sm_io_fprintf(smioout, "mail_pa=%S, ", ibdb_ta->ibt_mail_pa);
sm_io_fprintf(smioout, "\n");
#endif /* SM_TEST_PRT */
return SM_SUCCESS;
}
/*
** RCPT_ACTION -- Add recipient to DEFEDB (callback function)
**
** Parameters:
** info -- bht entry
** ctx -- context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
test_rcpt_action(bht_entry_P info, void *ctx)
{
sm_ret_T ret;
ibdb_rcpt_P ibdb_rcpt, ibdb_rcpt2;
te_ctx_P te_ctx;
te_ctx = (te_ctx_P) ctx;
ibdb_rcpt = (ibdb_rcpt_P) info->bhe_value;
if (ibdb_rcpt->ibr_ta_id == NULL)
return sm_err_perm(EINVAL);
++te_ctx->tex_nrcpts;
if (debug > 2)
sm_io_fprintf(smioout, "OPEN RCPT: ta=%s-%d\n",
ibdb_rcpt->ibr_ta_id,
ibdb_rcpt->ibr_idx);
ibdb_rcpt2 = bht_find(te_ctx->tex_rd_bhr, info->bhe_key,
SMTP_RCPTID_SIZE);
SM_TEST(ibdb_rcpt2 != NULL);
if (ibdb_rcpt2 == NULL)
{
/* OOPS what's going on? Where's our rcpt? */
sm_io_fprintf(smioout, "ERROR: bht_find(%s) failed\n", info->bhe_key);
return sm_err_perm(ENOENT);
}
#if 0
sm_io_fprintf(smioout, "rcpt_pa=%S, ", ibdb_rcpt->ibr_pa);
sm_io_fprintf(smioout, "rcpt_idx=%d, ", ibdb_rcpt->ibr_idx);
sm_io_fprintf(smioout, "\n");
#endif /* SM_TEST_PRT */
return SM_SUCCESS;
}
/*
** TESTIDB -- read IBDB
**
** Parameters:
** None
**
** Returns:
** usual sm_error code.
*/
static sm_ret_T
testidbr(void)
{
sm_ret_T ret;
ri_ctx_P ri_ctx;
bht_P bht, bhr;
te_ctx_T te_ctx;
bht = NULL;
bhr = NULL;
ret = sm_err_temp(ENOMEM);
bht = bht_new(BHTSIZE, BHTSIZE);
if (bht == NULL)
goto error;
bhr = bht_new(BHTSIZE, BHTSIZE);
if (bhr == NULL)
goto error;
te_ctx.tex_crt_bht = bht;
te_ctx.tex_crt_bhr = bhr;
te_ctx.tex_ntas = 0;
te_ctx.tex_nrcpts = 0;
ret = qm_ri_ctx_new(NULL, &ri_ctx);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
return ret;
te_ctx.tex_rd_bht = ri_ctx->rix_bht_ta;
te_ctx.tex_rd_bhr = ri_ctx->rix_bht_rcpt;
/* HACK */
ret = rdibdb(ri_ctx);
SM_TEST(ret == SM_SUCCESS);
/* check recipients first to count them for TAs */
bht_walk(bhr, test_rcpt_action, &te_ctx);
/* Now run through open transactions */
bht_walk(bht, test_ta_action, &te_ctx);
#if 0
/* don't match... open != all */
SM_TEST(ri_ctx->rix_ntas == te_ctx.tex_ntas );
SM_TEST(ri_ctx->rix_nrcpts == te_ctx.tex_nrcpts);
#endif /* 0 */
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "C#TAs: %u\n", te_ctx.tex_ntas);
sm_io_fprintf(smioout, "C#RCPTs: %u\n", te_ctx.tex_nrcpts);
sm_io_flush(smioout);
}
#endif /* SM_TEST_PRT */
/* HACK to avoid free... */
ri_ctx->rix_bht_ta = NULL;
ri_ctx->rix_bht_rcpt = NULL;
ret = qm_ri_ctx_free(ri_ctx);
SM_TEST(ret == SM_SUCCESS);
return ret;
error:
return ret;
}
static void
usage(const char *prg)
{
fprintf(stderr, "usage: %s [options]\n", prg);
fprintf(stderr, "-d n set debug level\n");
fprintf(stderr, "-I n initialize IBDB file number\n");
exit(1);
}
int
main(int argc, char *argv[])
{
int c;
sm_ret_T ret;
debug = 0;
while ((c = getopt(argc, argv, "d:I:")) != -1)
{
switch (c)
{
case 'd':
debug = strtoul(optarg, NULL, 0);
break;
case 'I':
init_seq = atoi(optarg);
break;
default:
usage(argv[0]);
return 1;
}
}
sm_test_begin(argc, argv, "test sm_idbr_2");
ret = testidbr();
return sm_test_end();
}
syntax highlighted by Code2HTML, v. 0.9.1