/*
* Copyright (c) 2002-2006 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_RCSID("@(#)$Id: qmgr_init.c,v 1.157 2007/10/23 04:01:41 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/qmgr.h"
#include "sm/evthr.h"
#include "sm/qmgr-int.h"
#include "sm/rdibdb.h"
#include "sm/fxszq.h"
#include "sm/hostname.h"
#include "sm/misc.h"
#include "sm/confsetpath.h"
#include "sm/rfc2821.h"
#include "qmgr.h"
/* XXX HACK XXX */
#define INIT_SEQ 1
sm_str_P NullSender;
#if QMGR_TEST
sm_cstr_P Tst_CDB_id;
#endif
/*
** QMGR_INIT0 -- initialize QMGR, step 0: set default values
** invoked before command line options are read
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** usual sm_error code
**
** Last code review: 2003-10-17 04:21:09
*/
sm_ret_T
qmgr_init0(qmgr_ctx_P qmgr_ctx)
{
uint u;
sm_ret_T ret;
#if QMGR_TEST
sessta_id_T ta_id;
#endif
/* should we allocate the context here? */
SM_REQUIRE(qmgr_ctx != NULL);
/* clear out data */
sm_memzero(qmgr_ctx, sizeof(*qmgr_ctx));
/* initialize fds (0 could be valid hence they need to be set) */
qmgr_ctx->qmgr_ss_li.qm_gli_lfd = INVALID_SOCKET;
qmgr_ctx->qmgr_ss_li.qm_gli_nfd = 0;
qmgr_ctx->qmgr_sc_li.qm_gli_lfd = INVALID_SOCKET;
qmgr_ctx->qmgr_sc_li.qm_gli_nfd = 0;
qmgr_ctx->qmgr_ar_fd = INVALID_SOCKET;
qmgr_ctx->qmgr_ctllfd = INVALID_SOCKET;
qmgr_ctx->qmgr_ctlfd = INVALID_SOCKET;
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_csize = IQDB_CSIZE;
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_htsize = IQDB_HTSIZE;
qmgr_ctx->qmgr_cnf.q_cnf_occ_size = OCC_CSIZE;
qmgr_ctx->qmgr_cnf.q_cnf_aq_size = AQ_SIZE;
qmgr_ctx->qmgr_cnf.q_cnf_optas = IBDB_OPEN_TAS;
qmgr_ctx->qmgr_cnf.q_cnf_ibdb_delay = IBDB_DELAY;
qmgr_ctx->qmgr_cnf.q_cnf_ibdb_size = IBDB_SIZE;
qmgr_ctx->qmgr_cnf.q_cnf_min_delay = MIN_DELAY_NXT_TRY;
qmgr_ctx->qmgr_cnf.q_cnf_max_delay = MAX_DELAY_NXT_TRY;
qmgr_ctx->qmgr_cnf.q_cnf_tmo_return = QM_TMO_RETURN;
qmgr_ctx->qmgr_cnf.q_cnf_tmo_delay = QM_TMO_DELAY;
qmgr_ctx->qmgr_cnf.q_cnf_tmo_ar = AQR_AR_TMOUT;
qmgr_ctx->qmgr_cnf.q_cnf_tmo_da = AQR_DA_TMOUT;
qmgr_ctx->qmgr_cnf.q_cnf_tmo_sched = AQR_SCHED_TMOUT;
qmgr_ctx->qmgr_tmo_sched = AQR_SCHED_TMOUT;
qmgr_ctx->qmgr_cnf.q_cnf_init_conc_conn = DA_INIT_CONC_CONN;
qmgr_ctx->qmgr_cnf.q_cnf_max_conc_conn = DA_MAX_CONC_CONN;
qmgr_ctx->qmgr_cnf.q_cnf_max_open_se = SS_MAX_OPEN_SE;
qmgr_ctx->qmgr_cnf.q_cnf_max_conn_rate = SS_MAX_CONN_RATE;
qmgr_ctx->qmgr_cnf.q_cnf_ss_cc_size = SS_CONNCTL_SIZE;
qmgr_ctx->qmgr_cnf.q_cnf_lmtp_rcpts_ta = DA_MAX_RCPTS_TA;
qmgr_ctx->qmgr_cnf.q_cnf_smtp_rcpts_ta = DA_MAX_RCPTS_TA;
qmgr_ctx->qmgr_cnf.q_cnf_t_sched_dsn = QM_TMO_SCHED_DSN;
qmgr_ctx->qmgr_cnf.q_cnf_dsn_rcpts_max = AQR_DSN_RCPTS_MAX;
qmgr_ctx->qmgr_cnf.q_cnf_min_df = DISK_MIN_FREE;
qmgr_ctx->qmgr_cnf.q_cnf_ok_df = DISK_OK_FREE;
qmgr_ctx->qmgr_cnf.q_cnf_edb_cnf.edbcnf_chkpt_delay = EDB_SWEEP_DELAY;
qmgr_ctx->qmgr_cnf.q_cnf_edb_cnf.edbcnf_oflags = EDB_OPEN_RECOVER
|EDB_LOG_AUTOREMOVE;
qmgr_ctx->qmgr_cnf.q_cnf_wait4srv = 1;
qmgr_ctx->qmgr_cnf.q_cnf_wait4clt = 1;
qmgr_ctx->qmgr_cnf.q_cnf_smarsock = smarsock;
qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock = smsmtpcsock;
qmgr_ctx->qmgr_cnf.q_cnf_smtpssock = smsmtpssock;
qmgr_ctx->qmgr_cnf.q_cnf_cdb_base = "";
qmgr_ctx->qmgr_cnf.q_cnf_ctlsock = NULL;
qmgr_ctx->qmgr_cnf.q_cnf_min_thr = SM_QMGR_MIN_THR;
qmgr_ctx->qmgr_cnf.q_cnf_max_thr = SM_QMGR_MAX_THR;
qmgr_ctx->qmgr_cnf.q_cnf_max_fd = SM_QMGR_MAX_FD;
qmgr_ctx->qmgr_cnf.q_cnf_loglevel = SM_LOG_LEVEL;
qmgr_ctx->qmgr_status = QMGR_ST_INIT0;
NullSender = sm_str_scpy(NULL, "<>", 4);
ret = sm_log_create(NULL, &qmgr_ctx->qmgr_lctx, &qmgr_ctx->qmgr_lcfg);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init0, sm_log_create=%m\n", ret);
goto error;
}
ret = sm_log_setfp_fd(qmgr_ctx->qmgr_lctx, smiolog, SMIOLOG_FILENO);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init0, sm_log_setfp=%m\n", ret);
goto error;
}
ret = sm_log_setdebuglevel(qmgr_ctx->qmgr_lctx, qmgr_ctx->qmgr_cnf.q_cnf_loglevel);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init0, sm_log_setdebuglevel=%m\n",
ret);
goto error;
}
#define SM_UPPER_CACHE_LIMIT 90
#define SM_LOWER_CACHE_LIMIT 70
for (u = 0; u <= QMGR_RFL_LAST_I; u++) {
qmgr_ctx->qmgr_lower[u] = SM_LOWER_CACHE_LIMIT;
qmgr_ctx->qmgr_upper[u] = SM_UPPER_CACHE_LIMIT;
}
#if 0
/* set lower limit for disk space? */
for (u = QMGR_RFL_CDB_I; u <= QMGR_RFL_LAST_I; u++)
qmgr_ctx->qmgr_lower[u] = 0;
#endif /* 0 */
#if QMGR_TEST
sm_snprintf(ta_id, SMTP_STID_SIZE, SMTPS_STID_FORMAT, (id_count_T)0, 0);
Tst_CDB_id = sm_cstr_scpyn((const uchar *)ta_id, sizeof(ta_id));
if (NULL == Tst_CDB_id)
return sm_error_temp(SM_EM_Q, ENOMEM);
#endif
/* this is a bit early ... */
qmgr_ctx->sm_magic = SM_QMGR_CTX_MAGIC;
qmgr_ctx->qmgr_cnf.sm_magic = SM_QMGR_CNF_MAGIC;
return SM_SUCCESS;
error:
return ret;
}
/*
** QMGR_INIT1 -- initialize QMGR
** invoked after command line options are read
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** usual sm_error code
**
** Last code review: 2003-10-17 04:37:37, see below
*/
sm_ret_T
qmgr_init1(qmgr_ctx_P qmgr_ctx)
{
int i;
sm_ret_T ret;
size_t n;
sm_evthr_ctx_P ev_ctx;
qss_opta_P optas;
sm_cstr_P mtype, mname;
size_t confdirlen;
const char *mpath;
char confdir[PATH_MAX];
SM_REQUIRE(qmgr_ctx != NULL);
ev_ctx = NULL;
/*
** Output error message?
** Complicated: the logging system isn't initialized yet
** (it's done somewhere in the middle). For now: use smioerr.
*/
if (NULL == qmgr_ctx->qmgr_hostname) {
ret = sm_myhostname(&qmgr_ctx->qmgr_hostname);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, sm_myhostname=%m\n"
, ret);
goto err0;
}
}
if (NULL == qmgr_ctx->qmgr_pm_addr &&
NULL == qmgr_ctx->qmgr_cnf.q_cnf_pm_add)
{
n = sm_str_getlen(qmgr_ctx->qmgr_hostname) +
strlen("<postmaster@>") + 2;
qmgr_ctx->qmgr_pm_addr = sm_str_new(NULL, n, n + 1);
if (NULL == qmgr_ctx->qmgr_pm_addr) {
/* other error codes? */
ret = sm_error_temp(SM_EM_Q, ENOMEM);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, init=out_of_memory\n");
goto err0;
}
if (sm_is_err(ret = sm_str_scopy(qmgr_ctx->qmgr_pm_addr,
"<postmaster@")) ||
sm_is_err(ret = sm_str_cat(qmgr_ctx->qmgr_pm_addr,
qmgr_ctx->qmgr_hostname)) ||
sm_is_err(ret = sm_str_scat(qmgr_ctx->qmgr_pm_addr, ">")))
{
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, scopy=%m\n", ret);
goto err0;
}
}
else if (NULL == qmgr_ctx->qmgr_pm_addr &&
NULL != qmgr_ctx->qmgr_cnf.q_cnf_pm_add)
{
sm_a2821_T addr;
n = strlen(qmgr_ctx->qmgr_cnf.q_cnf_pm_add) + 1;
qmgr_ctx->qmgr_pm_addr = sm_str_scpy(NULL,
qmgr_ctx->qmgr_cnf.q_cnf_pm_add, n);
if (NULL == qmgr_ctx->qmgr_pm_addr) {
/* other error codes? */
ret = sm_error_temp(SM_EM_Q, ENOMEM);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, init=out_of_memory\n");
goto err0;
}
A2821_INIT_RP(&addr, NULL);
ret = t2821_scan((sm_rdstr_P) qmgr_ctx->qmgr_pm_addr, &addr, 0);
if (!sm_is_err(ret))
ret = t2821_parse(&addr, R2821_CORRECT|R2821_EMPTY);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, address=\"%@s\", status=invalid, parse=%m\n",
qmgr_ctx->qmgr_cnf.q_cnf_pm_add, ret);
SM_STR_FREE(qmgr_ctx->qmgr_pm_addr);
goto err0;
}
(void) a2821_free(&addr);
}
ret = sm_dirname(qmgr_ctx->qmgr_cnf.q_cnf_conffile, confdir,
sizeof(confdir));
if (sm_is_err(ret))
goto err0;
confdirlen = strlen(confdir);
/* initialize control RCB only if socket is specified */
if (qmgr_ctx->qmgr_cnf.q_cnf_ctlsock != NULL &&
*qmgr_ctx->qmgr_cnf.q_cnf_ctlsock != '\0')
{
ret = sm_rcbcom_open(&qmgr_ctx->qmgr_ctl_com);
if (sm_is_err(ret))
goto err0;
}
ret = sm_gen_conf_path(qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
qmgr_ctx->qmgr_cnf.q_cnf_smtpssock,
smsmtpssock,
&qmgr_ctx->qmgr_cnf.q_cnf_smtpssock_abs,
&qmgr_ctx->qmgr_cnf.q_cnf_smtpssock_alloc);
if (sm_is_err(ret))
return ret;
ret = sm_gen_conf_path(qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock,
smsmtpcsock,
&qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock_abs,
&qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock_alloc);
if (sm_is_err(ret))
return ret;
ret = sm_gen_conf_path(qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
qmgr_ctx->qmgr_cnf.q_cnf_smarsock,
smarsock,
&qmgr_ctx->qmgr_cnf.q_cnf_smarsock_abs,
&qmgr_ctx->qmgr_cnf.q_cnf_smarsock_alloc);
if (sm_is_err(ret))
return ret;
if (qmgr_ctx->qmgr_cnf.q_cnf_ctlsock != NULL &&
*qmgr_ctx->qmgr_cnf.q_cnf_ctlsock != '\0') {
ret = sm_gen_conf_path(qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
qmgr_ctx->qmgr_cnf.q_cnf_ctlsock,
NULL,
&qmgr_ctx->qmgr_cnf.q_cnf_ctlsock_abs,
&qmgr_ctx->qmgr_cnf.q_cnf_ctlsock_alloc);
if (sm_is_err(ret))
return ret;
}
ret = cdb_start(qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
&qmgr_ctx->qmgr_cdb_ctx);
if (sm_is_err(ret))
return ret;
qmgr_ctx->qmgr_iqdb = iqdb_open(qmgr_ctx->qmgr_cnf.q_cnf_iqdb_csize,
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_htsize,
qm_iqdb_create, NULL, qmgr_ctx);
if (NULL == qmgr_ctx->qmgr_iqdb) {
/* other error codes? */
ret = sm_error_temp(SM_EM_Q, ENOMEM);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, iqdb_open=out_of_memory\n");
goto err0;
}
/* initialize pthreads */
ret = thr_init();
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, thr_init=%m\n", ret);
goto err1;
}
i = pthread_mutex_init(&qmgr_ctx->qmgr_mutex, SM_PTHREAD_MUTEXATTR);
if (i != 0) {
ret = sm_error_perm(SM_EM_Q, i);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, mutex_init=%m\n", i);
goto err2;
}
/* initialize RCB list */
RCBL_INIT(&qmgr_ctx->qmgr_rcbh);
/* initialize event threads system */
ret = evthr_init(&ev_ctx,
qmgr_ctx->qmgr_cnf.q_cnf_min_thr,
qmgr_ctx->qmgr_cnf.q_cnf_max_thr,
qmgr_ctx->qmgr_cnf.q_cnf_max_fd);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, evthr_init=%m\n", ret);
goto err3;
}
#if EVTHR_DEBUG
evthr_set_dbglvl(ev_ctx, qmgr_ctx->qmgr_evthr_dbg_lvl);
#endif
/*
** HACK! it should check whether log is in config file
** however it's not clear how to do that...
** this only works because facility 0 is KERN.
*/
if (qmgr_ctx->qmgr_cnf.q_cnf_log.sm_logspc_facility != 0) {
ret = sm_log_setfp_fd(ev_ctx->evthr_c_lctx, NULL, INVALID_FD);
if (sm_is_err(ret))
goto err5;
}
ret = sm_log_setdebuglevel(qmgr_ctx->qmgr_lctx, qmgr_ctx->qmgr_cnf.q_cnf_loglevel);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, sm_log_setdebuglevel=%m\n",
ret);
goto err5;
}
/* create SMTPS contexts */
for (i = 0; i < QM_N_SS_GLI(qmgr_ctx); i++) {
ret = qss_ctx_new(qmgr_ctx,
(qss_ctx_P *) &(qmgr_ctx->qmgr_ss_li.qm_gli_ctx[i]));
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, qss_ctx_new=%m, i=%d\n",
ret, i);
goto err5;
}
}
qmgr_ctx->qmgr_ss_li.qm_gli_fct = qmgr_smtps;
qmgr_ctx->qmgr_ss_li.qm_gli_qmgr_ctx = qmgr_ctx;
qmgr_ctx->qmgr_ss_li.sm_magic = SM_GLI_MAGIC;
/* initialize open transactions */
optas = (qss_opta_P) sm_malloc(sizeof(*optas));
if (NULL == optas) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, optas_malloc=out_of_memory\n");
goto err5;
}
FSQ_INIT(qmgr_ctx->qmgr_cnf.q_cnf_optas, optas->qot_max,
optas->qot_cur, optas->qot_first, optas->qot_last);
n = optas->qot_max * sizeof(*optas->qot_tas);
optas->qot_tas = (qss_ta_P *) sm_zalloc(n);
if (NULL == optas->qot_tas) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, optas_qot_tas_malloc=out_of_memory\n");
goto err6;
}
i = pthread_mutex_init(&optas->qot_mutex, SM_PTHREAD_MUTEXATTR);
if (i != 0) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, mutex_init=%i\n", i);
ret = sm_error_perm(SM_EM_Q, i);
goto err7;
}
/* create SMTPC contexts */
for (i = 0; i < QM_N_SC_GLI(qmgr_ctx); i++) {
ret = qsc_ctx_new(qmgr_ctx, (uint32_t) i,
(qsc_ctx_P *) &(qmgr_ctx->qmgr_sc_li.qm_gli_ctx[i]));
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, qsc_ctx_new=%m\n",
ret);
goto err8;
}
}
qmgr_ctx->qmgr_sc_li.qm_gli_fct = qmgr_smtpc;
qmgr_ctx->qmgr_sc_li.qm_gli_qmgr_ctx = qmgr_ctx;
qmgr_ctx->qmgr_sc_li.sm_magic = SM_GLI_MAGIC;
/* open active envelope db */
ret = aq_open(qmgr_ctx, &qmgr_ctx->qmgr_aq,
qmgr_ctx->qmgr_cnf.q_cnf_aq_size, 0);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, aq_open=%m\n", ret);
goto err8;
}
null_cdb_id = sm_cstr_scpyn((const uchar *) "-", 1);
if (NULL == null_cdb_id) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, cstr_scpyn=out_of_memory\n");
goto err9;
}
ret = qar_ctx_new(qmgr_ctx, &qmgr_ctx->qmgr_ar_ctx);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, qar_ctx_new=%m\n", ret);
goto err10;
}
/* Must be set before qm_rdibdb() is called */
qmgr_ctx->qmgr_ev_ctx = ev_ctx;
/* max. number of directories in different FSs */
#define FS_DB_DIRS 32
ret = fs_ctx_open(FS_DB_DIRS, &qmgr_ctx->qmgr_fs_ctx);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, fs_ctx_open=%m\n", ret);
goto err11;
}
ret = cdb_fsctx_open(qmgr_ctx->qmgr_fs_ctx,
(const char *)qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
&qmgr_ctx->qmgr_cdb_fsctx,
&qmgr_ctx->qmgr_cdb_kbfree);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, cdb_fsctx_open=%m\n", ret);
goto err12;
}
/* XXX Move this after edb_open()? */
ret = edb_fsctx_open(qmgr_ctx->qmgr_fs_ctx,
(const char *)qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
&qmgr_ctx->qmgr_edb_fsctx, &qmgr_ctx->qmgr_edb_kbfree);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, edb_fsctx_open=%m\n", ret);
goto err13;
}
ret = edb_open(&qmgr_ctx->qmgr_cnf.q_cnf_edb_cnf,
(const char *)qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
qmgr_ctx->qmgr_lctx, &qmgr_ctx->qmgr_edb);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, edb_open=%m\n", ret);
goto error;
}
ret = edbc_open(&qmgr_ctx->qmgr_edbc, 0, 0);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, edbc_open=%m\n", ret);
goto error;
}
/* must be done after DEFEDB, before IBDB */
ret = qm_rdibdb(qmgr_ctx);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, qm_rdibdb=%m\n", ret);
goto error;
}
/* open ibdb, must be done after qm_rdibdb() */
ret = ibdb_open((const char *)qmgr_ctx->qmgr_cnf.q_cnf_cdb_base,
IBDB_NAME, SM_IO_WRONLY, INIT_SEQ,
qmgr_ctx->qmgr_cnf.q_cnf_ibdb_size, IBDB_OFL_WRITE,
qmgr_ctx->qmgr_fs_ctx,
&qmgr_ctx->qmgr_ibdb);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, ibdb_open=%m\n", ret);
goto error;
}
ret = ibdb_fs_getfree(qmgr_ctx->qmgr_ibdb,
&qmgr_ctx->qmgr_ibdb_kbfree);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_init1, ibdb_fs_getfree=%m\n", ret);
goto error;
}
/* XXX write dummy record to IBDB to keep track of last id? */
ret = sm_maps_init(&qmgr_ctx->qmgr_maps);
if (NULL == qmgr_ctx->qmgr_maps) {
ret = sm_error_temp(SM_EM_Q, ENOMEM);
goto error;
}
ret = sm_bdb_class_create(qmgr_ctx->qmgr_maps);
if (sm_is_err(ret))
goto error;
#define QMGR_CONF_TYPE "hash"
#define QMGR_CONF_NAME "qmgr_conf"
#define QMGR_CONF_FILE "qmgr_conf.db"
mtype = sm_cstr_scpyn0((const uchar *)QMGR_CONF_TYPE,
strlen(QMGR_CONF_TYPE));
if (NULL == mtype) {
ret = sm_error_temp(SM_EM_Q, ENOMEM);
goto error;
}
mname = sm_cstr_scpyn0((const uchar *)QMGR_CONF_NAME,
strlen(QMGR_CONF_NAME));
if (NULL == mname) {
ret = sm_error_temp(SM_EM_Q, ENOMEM);
goto error;
}
qmgr_ctx->qmgr_conf_map = NULL;
SM_GEN_MAP_PATH(mpath, qmgr_ctx->qmgr_cnf.q_cnf_confmap_path, confdir,
qmgr_ctx->qmgr_cnf.q_cnf_confmap_fn, QMGR_CONF_FILE, error);
ret = sm_map_open(qmgr_ctx->qmgr_maps, mname, mtype, 0,
mpath, SMAP_MODE_RDONLY,
&qmgr_ctx->qmgr_conf_map, SMPO_END);
/* ignore errors for now, the map is optional... */
if (sm_is_err(ret)) {
QM_LEV_DPRINTFC(QDC_INIT, 3, (QM_DEBFP, "func=qmgr_init1, sm_map_open=%r, map=%p\n", ret, qmgr_ctx->qmgr_conf_map));
qmgr_ctx->qmgr_conf_map = NULL;
#if 0
goto error;
#endif /* 0 */
}
qmgr_ctx->qmgr_optas = optas;
qmgr_ctx->qmgr_status = QMGR_ST_INIT1;
return SM_SUCCESS;
/*
** Error handling. Notice: to get rid of all these "goto errorXY"
** which complicates changing the order, all variables should
** be initialized to NULL (or another unique value which indicates
** that the _open()/_new() function hasn't been called yet). The
** _close()/_free() functions should allow NULL as value
** and simply return SM_SUCCESS. Then the functions can be
** called in no specific order except for a few like
** thread/mutex initialization.
*/
error:
edbc_close(qmgr_ctx->qmgr_edbc);
qmgr_ctx->qmgr_edbc = NULL;
(void) edb_close(qmgr_ctx->qmgr_edb);
qmgr_ctx->qmgr_edb = NULL;
(void) edb_fsctx_close(qmgr_ctx->qmgr_edb_fsctx);
err13:
(void) cdb_fsctx_close(qmgr_ctx->qmgr_cdb_fsctx);
err12:
(void) fs_ctx_close(qmgr_ctx->qmgr_fs_ctx);
qmgr_ctx->qmgr_fs_ctx = NULL;
err11:
(void) qar_ctx_free(qmgr_ctx->qmgr_ar_ctx);
qmgr_ctx->qmgr_ar_ctx = NULL;
err10:
SM_CSTR_FREE(null_cdb_id);
err9:
aq_close(qmgr_ctx->qmgr_aq);
qmgr_ctx->qmgr_aq = NULL;
err8:
/* qsc_ctx_free() can deal with NULL values */
for (i = 0; i < QM_N_SC_GLI(qmgr_ctx); i++) {
(void) qsc_ctx_free(qmgr_li_sc(qmgr_ctx, i));
qmgr_li_sc_lv(qmgr_ctx, i) = NULL;
}
err7:
SM_FREE(optas->qot_tas);
err6:
SM_FREE(optas);
err5:
/* qss_ctx_free() can deal with NULL values */
for (i = 0; i < QM_N_SS_GLI(qmgr_ctx); i++) {
(void) qss_ctx_free(qmgr_li_ss(qmgr_ctx, i));
qmgr_li_ss_lv(qmgr_ctx, i) = NULL;
}
if (qmgr_ctx->qmgr_ibdb != NULL) {
ibdb_close(qmgr_ctx->qmgr_ibdb);
qmgr_ctx->qmgr_ibdb = NULL;
}
sm_log_destroy(qmgr_ctx->qmgr_lctx);
/* err4: */
if (ev_ctx != NULL) {
(void) evthr_stop(ev_ctx);
ev_ctx = NULL;
}
err3:
(void) pthread_mutex_destroy(&qmgr_ctx->qmgr_mutex);
err2:
(void) thr_stop();
err1:
/* this should always be true, but better safe than sorry */
if (qmgr_ctx->qmgr_iqdb != NULL) {
iqdb_close(qmgr_ctx->qmgr_iqdb);
qmgr_ctx->qmgr_iqdb = NULL;
}
err0:
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1