/* * 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("") + 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, "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; }