/*
* Copyright (c) 2002-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_RCSID("@(#)$Id: qmgr_start.c,v 1.127 2007/06/18 04:42:31 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "sm/unixsock.h"
#include "sm/signal.h"
#include "sm/resource.h"
#include "sm/misc.h"
#include "qmgr.h"
#include "log.h"
/*
** QM_LISTEN -- start one QMGR listener
**
** Parameters:
** sockname -- path for (Unix domain) socket
** XXX Needs to be fixed for Windows!
** pfd -- (pointer to) fd (output)
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
qm_listen(const char *sockname, int *pfd)
{
int lfd, r;
sm_ret_T ret;
SM_REQUIRE(sockname != NULL);
SM_REQUIRE(pfd != NULL);
ret = SM_SUCCESS;
r = unlink(sockname);
if (r < 0 && errno != ENOENT) {
ret = sm_error_perm(SM_EM_Q_START, errno);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_listen, socket=%s, unlink=%m\n",
sockname, ret);
goto error;
}
lfd = unix_server_listen(sockname, 10);
if (!is_valid_socket(lfd)) {
ret = sm_error_perm(SM_EM_Q_START, errno);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_listen, socket=%s, unix_server_listen=%m\n",
sockname, lfd);
goto error;
}
r = chmod(sockname, 0660);
if (r < 0) {
ret = sm_error_perm(SM_EM_Q_START, errno);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_listen, socket=%s, chmod=%m\n",
sockname, ret);
goto error;
}
*pfd = lfd;
/* FALLTHROUGH */
error:
return ret;
}
/*
** QM_STLI -- start QMGR listeners
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** usual sm_error code
**
** Question: should we store "task" in qmgr_ctx?
*/
static sm_ret_T
qm_stli(qmgr_ctx_P qmgr_ctx)
{
int fd;
uint u;
sm_ret_T ret;
sm_evthr_task_P task;
SM_IS_QMGR_CTX(qmgr_ctx);
/* start listen connections */
/* these should be in qmgr_ctx after the configuration has been read */
/* SMTPS */
ret = qm_listen(qmgr_ctx->qmgr_cnf.q_cnf_smtpssock_abs, &fd);
if (sm_is_err(ret))
goto error;
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_LI,
fd, NULL, qm_gen_li, (void *) &qmgr_ctx->qmgr_ss_li);
if (sm_is_err(ret))
goto error;
qmgr_ctx->qmgr_ss_li.qm_gli_lfd = fd;
/* SMTPC (XXX just for now, later on QMGR requests SMTPC to start) */
ret = qm_listen(qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock_abs, &fd);
if (sm_is_err(ret))
goto error;
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_LI,
fd, NULL, qm_gen_li, (void *) &qmgr_ctx->qmgr_sc_li);
if (sm_is_err(ret))
goto error;
qmgr_ctx->qmgr_sc_li.qm_gli_lfd = fd;
/* control socket */
if (qmgr_ctx->qmgr_cnf.q_cnf_ctlsock_abs != NULL &&
*qmgr_ctx->qmgr_cnf.q_cnf_ctlsock_abs != '\0')
{
ret = qm_listen(qmgr_ctx->qmgr_cnf.q_cnf_ctlsock_abs, &fd);
if (sm_is_err(ret))
goto error;
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_LI,
fd, NULL, qm_ctl_li, (void *) qmgr_ctx);
if (sm_is_err(ret))
goto error;
qmgr_ctx->qmgr_ctllfd = fd;
}
fd = INVALID_SOCKET;
/* simple loop: count seconds, sleep(1) is used */
for (u = 0;
u < qmgr_ctx->qmgr_cnf.q_cnf_wait4srv && !is_valid_socket(fd);
u++)
{
#if SMAR_TCP_NET
ret = net_client_connect(smarip, smarport, &fd);
#else
ret = unix_client_connect(qmgr_ctx->qmgr_cnf.q_cnf_smarsock_abs, &fd);
#endif
if (!is_valid_socket(fd))
sleep(1);
else
break;
}
if (!is_valid_socket(fd)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_stli, socket=%s, unix_client_connect=%m\n",
qmgr_ctx->qmgr_cnf.q_cnf_smarsock_abs, ret);
goto error;
}
qmgr_ctx->qmgr_ar_fd = fd;
ret = sm_rcb_open_rcv(qmgr_ctx->qmgr_ar_ctx->qar_com.rcbcom_rdrcb);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_stli, sm_rcb_open_rcv=%m\n",
ret);
goto error;
}
ret = sm_fd_nonblock(fd, true);
if (sm_is_err(ret))
goto error; /* XXX COMPLAIN */
/* start a task for the new AR */
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &qmgr_ctx->qmgr_ar_tsk,
EVTHR_EV_RD, fd, NULL, qmgr_ar, qmgr_ctx->qmgr_ar_ctx);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qm_stli, evthr_task_new=%m\n",
ret);
goto error;
}
SM_IS_EVTHR_TSK(qmgr_ctx->qmgr_ar_tsk);
qmgr_ctx->qmgr_ar_ctx->qar_com.rcbcom_tsk = qmgr_ctx->qmgr_ar_tsk;
if (sm_is_err(ret))
goto error;
QM_LEV_DPRINTFC(QDC_START, 6, (QM_DEBFP, "sev=DBG, func=qm_stli, status=OK\n"));
qmgr_ctx->qmgr_st_time = evthr_time(qmgr_ctx->qmgr_ev_ctx);
return SM_SUCCESS;
error:
CLOSE_FD(qmgr_ctx->qmgr_ss_li.qm_gli_lfd);
CLOSE_FD(qmgr_ctx->qmgr_sc_li.qm_gli_lfd);
CLOSE_FD(qmgr_ctx->qmgr_ar_fd);
return ret;
}
/*
** QM_REOPEN_MAPS -- reopen QMGR maps
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** usual sm_error code
*/
sm_ret_T
qm_reopen_maps(qmgr_ctx_P qmgr_ctx)
{
sm_ret_T ret;
SM_IS_QMGR_CTX(qmgr_ctx);
/* reload map(s) */
ret = SM_SUCCESS;
if (qmgr_ctx->qmgr_conf_map != NULL) {
ret = sm_map_reopen(qmgr_ctx->qmgr_conf_map, 0, SMPO_END);
if (sm_is_err(ret)) {
/* qmgr_ctx->qmgr_conf_map = NULL; */
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_CONTROL, QM_LMOD_SCHED,
SM_LOG_ERR, 2,
"sev=ERROR, func=qm_reopen_maps, sm_map_reopen=%m",
ret);
}
}
return SM_SUCCESS;
}
/*
** QM_INFO -- print current usage and configuration
**
** Parameters:
** qmgr_ctx -- QMGR context
** fp -- file pointer for output
**
** Returns:
** usual sm_error code
*/
sm_ret_T
qm_info(qmgr_ctx_P qmgr_ctx, sm_file_T *fp)
{
int r;
uint32_t j;
uint u;
struct rusage rusage;
#if SM_BHT_PERF
char out[1024];
#endif
SM_IS_QMGR_CTX(qmgr_ctx);
if (qmgr_ctx->qmgr_ev_ctx != NULL) {
time_T now;
now = evthr_time(qmgr_ctx->qmgr_ev_ctx);
sm_io_fprintf(fp, "[");
(void) sm_timestamp(now, fp);
sm_io_fprintf(fp, "] sev=INFO, where=qmgr_usr1\n");
}
#if SM_HEAP_CHECK
sm_io_fprintf(fp, "sev=INFO, func=qm_info\n");
if (HEAP_CHECK)
sm_heap_report(fp, 3);
#endif
/* configuration */
qmgr_prt_cnf(&qmgr_ctx->qmgr_cnf, fp, true);
/* print only active entries? */
for (j = 1, r = 0; r < QM_N_SS_GLI(qmgr_ctx); r++, j *= 2)
{
qss_ctx_P qss_ctx;
if (0 == (qmgr_ctx->qmgr_ss_li.qm_gli_used & j) ||
(qss_ctx = qmgr_li_ss(qmgr_ctx, r)) == NULL)
continue;
sm_io_fprintf(fp,
"qss_max_thrs [%2d] =%7u\n"
"qss_max_cur_thrds[%2d] =%7u\n"
"qss_cur_session [%2d] =%7u\n"
, r, qss_ctx->qss_max_thrs
, r, qss_ctx->qss_max_cur_thrs
, r, qss_ctx->qss_cur_session
);
}
for (r = 0; r < QM_N_SC_GLI(qmgr_ctx); r++)
{
qsc_ctx_P qsc_ctx;
if ((qsc_ctx = qmgr_li_sc(qmgr_ctx, r)) == NULL ||
qsc_ctx->qsc_dadb_ctx == NULL)
continue;
#if 0
sm_io_fprintf(fp, "qsc_curactive [%2d] =%7u\n",
r, qmgr_ctx->qmgr_scctx[r]->qsc_curactive);
sm_io_fprintf(fp, "qsc_maxthreads [%2d] =%7u\n",
r, qmgr_ctx->qmgr_scctx[r]->qsc_maxthreads);
#else /* 0 */
sm_io_fprintf(fp, "dadb_entries_cur [%2d] =%7u\n", r,
qsc_ctx->qsc_dadb_ctx->dadb_entries_cur);
sm_io_fprintf(fp, "dadb_entries_idle[%2d] =%7u\n", r,
qsc_ctx->qsc_dadb_ctx->dadb_entries_idle);
sm_io_fprintf(fp, "dadb_entries_lim [%2d] =%7u\n", r,
qsc_ctx->qsc_dadb_ctx->dadb_entries_lim);
sm_io_fprintf(fp, "dadb_entries_max [%2d] =%7u\n", r,
qsc_ctx->qsc_dadb_ctx->dadb_entries_max);
#if DADB_STATS
sm_io_fprintf(fp, "dadb_entries_used[%2d] =%7u\n", r,
qsc_ctx->qsc_dadb_ctx->dadb_entries_max_used);
#endif
#endif /* 0 */
}
#if QMGR_STATS
sm_io_fprintf(fp, "Transactions received=%7lu\n",
qmgr_ctx->qmgr_tas_rcvd);
sm_io_fprintf(fp, "Recipients received =%7lu\n",
qmgr_ctx->qmgr_rcpts_rcvd);
sm_io_fprintf(fp, "Transactions sent =%7lu\n",
qmgr_ctx->qmgr_tas_sent);
sm_io_fprintf(fp, "Recipients sent =%7lu\n",
qmgr_ctx->qmgr_rcpts_sent);
#endif /* QMGR_STATS */
sm_io_fprintf(fp, "IQDB usage =%7u %%\n",
iqdb_usage(qmgr_ctx->qmgr_iqdb));
sm_io_fprintf(fp, "IQDB current =%7u\n",
iqdb_entries(qmgr_ctx->qmgr_iqdb, &u));
sm_io_fprintf(fp, "IQDB max_used =%7u\n", u);
sm_io_fprintf(fp, "AQ usage (all) =%7u %%\n",
aq_usage(qmgr_ctx->qmgr_aq, AQ_USAGE_ALL));
sm_io_fprintf(fp, "AQ usage (defedb) =%7u %%\n",
aq_usage(qmgr_ctx->qmgr_aq, AQ_USAGE_DEFEDB));
sm_io_fprintf(fp, "AQ current =%7u\n",
qmgr_ctx->qmgr_aq->aq_entries);
#if AQ_STATS
sm_io_fprintf(fp, "AQ waitq current =%7u\n",
qmgr_ctx->qmgr_aq->aq_waitq_entries);
sm_io_fprintf(fp, "AQ waitq max_used =%7u\n",
qmgr_ctx->qmgr_aq->aq_waitq_max);
#endif
sm_io_fprintf(fp, "AQ rdq max_used =%7u\n",
qmgr_ctx->qmgr_aq->aq_rdq_used_max);
sm_io_fprintf(fp, "EDBC current =%7u\n",
qmgr_ctx->qmgr_edbc->edbc_entries);
sm_io_fprintf(fp, "IBDB kbfree =%7lu\n",
qmgr_ctx->qmgr_ibdb_kbfree);
sm_io_fprintf(fp, "CDB kbfree =%7lu\n",
qmgr_ctx->qmgr_cdb_kbfree);
sm_io_fprintf(fp, "EDB kbfree =%7lu\n",
qmgr_ctx->qmgr_edb_kbfree);
sm_io_fprintf(fp, "qmgr_rflags =%#08x\n",
qmgr_ctx->qmgr_rflags);
sm_io_fprintf(fp, "qmgr_sflags =%#08x\n",
qmgr_ctx->qmgr_sflags);
sm_io_fprintf(fp, "qmgr_total_usage =%3u %%\n",
qmgr_ctx->qmgr_total_usage);
for (u = 0; u <= QMGR_RFL_LAST_I; u++)
{
sm_io_fprintf(fp, "qmgr_usage[%d] =%3u %%\n",
u, qmgr_ctx->qmgr_usage[u]);
#if QMGR_STATS
sm_io_fprintf(fp, "qmgr_max_use[%d] =%3u %%\n",
u, qmgr_ctx->qmgr_max_use[u]);
#endif
}
(void) ibdb_stats(qmgr_ctx->qmgr_ibdb, fp);
(void) ibdbc_show_seq(qmgr_ctx->qmgr_ibdb, THR_LOCK_UNLOCK, fp);
(void) edb_status(qmgr_ctx->qmgr_edb, fp);
#if 0 && SM_BHT_PERF
/* which table(s)? */
sm_bht_stats(table, out, sizeof(out));
#endif
(void) occ_print(qmgr_ctx->qmgr_occ_ctx, fp, THR_LOCK_UNLOCK);
r = getrusage(RUSAGE_SELF, &rusage);
if (0 == r) {
sm_io_fprintf(fp,
"ru_utime= %7ld.%07ld s\n"
"ru_stime= %7ld.%07ld s\n"
"ru_maxrss= %7ld\n"
"ru_ixrss= %7ld\n"
"ru_idrss= %7ld\n"
"ru_isrss= %7ld\n"
"ru_minflt= %7ld\n"
"ru_majflt= %7ld\n"
"ru_nswap= %7ld\n"
"ru_inblock= %7ld\n"
"ru_oublock= %7ld\n"
"ru_msgsnd= %7ld\n"
"ru_msgrcv= %7ld\n"
"ru_nsignals=%7ld\n"
"ru_nvcsw= %7ld\n"
"ru_nivcsw= %7ld\n"
, rusage.ru_utime.tv_sec
, rusage.ru_utime.tv_usec
, rusage.ru_stime.tv_sec
, rusage.ru_stime.tv_usec
, rusage.ru_maxrss
, rusage.ru_ixrss
, rusage.ru_idrss
, rusage.ru_isrss
, rusage.ru_minflt
, rusage.ru_majflt
, rusage.ru_nswap
, rusage.ru_inblock
, rusage.ru_oublock
, rusage.ru_msgsnd
, rusage.ru_msgrcv
, rusage.ru_nsignals
, rusage.ru_nvcsw
, rusage.ru_nivcsw
);
}
(void) sm_io_flush(fp);
return SM_SUCCESS;
}
/*
** QM_USR1 -- task handler for SIGUSR1
** print current usage and configuration
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** EVTHR_WAITQ
*/
static sm_ret_T
qm_usr1(sm_evthr_task_P tsk)
{
qmgr_ctx_P qmgr_ctx;
SM_IS_EVTHR_TSK(tsk);
qmgr_ctx = (qmgr_ctx_P) tsk->evthr_t_actx;
SM_IS_QMGR_CTX(qmgr_ctx);
(void) qm_reopen_maps(qmgr_ctx);
(void) qm_info(qmgr_ctx, smioout);
return EVTHR_WAITQ;
}
/*
** QM_USR2 -- task handler for SIGUSR2
** reopen logfiles (useful for log rotation right now, should be
** handled differently later, e.g., see isc log module)
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** EVTHR_WAITQ
*/
static sm_ret_T
qm_usr2(sm_evthr_task_P tsk)
{
qmgr_ctx_P qmgr_ctx;
SM_IS_EVTHR_TSK(tsk);
qmgr_ctx = (qmgr_ctx_P) tsk->evthr_t_actx;
SM_IS_QMGR_CTX(qmgr_ctx);
(void) sm_log_reopen(qmgr_ctx->qmgr_lctx);
return EVTHR_WAITQ;
}
/*
** QMGR_START -- start QMGR
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** usual sm_error code
**
** Last code review: 2003-10-24 17:29:23
*/
sm_ret_T
qmgr_start(qmgr_ctx_P qmgr_ctx)
{
sm_ret_T ret;
timeval_T now, sleept, delay;
sm_evthr_task_P task;
ibdb_rcpt_T ibdb_rcpt;
sessta_id_T ta_id;
SM_IS_QMGR_CTX(qmgr_ctx);
sm_memzero(&ibdb_rcpt, sizeof(ibdb_rcpt));
sm_memzero(&ta_id, sizeof(ta_id));
ret = ssocc_open(&qmgr_ctx->qmgr_ssocc_ctx,
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_htsize,
qmgr_ctx->qmgr_cnf.q_cnf_ss_cc_size);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, ssocc_open=%m", ret);
goto error;
}
ret = occ_open(&qmgr_ctx->qmgr_occ_ctx, qmgr_ctx->qmgr_cnf.q_cnf_occ_size);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, occ_open=%m", ret);
goto error;
}
ret = evthr_timeval(qmgr_ctx->qmgr_ev_ctx, &now);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, evthr_timeval=%m", ret);
goto error;
}
/* XXX is it ok to run this that early? */
ret = qm_edb_scan(qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, qm_edb_scan=%m", ret);
goto error;
}
/*
** Add a dummy record to IBDB; must be added/removed otherwise IBDB
** will complain.
** The dummy record is there to keep track of the latest id counter
** for SMTPS in case QMGR is restarted without receiving a new
** transaction.
** Note: there's a race condition: IBDB is removed in qmgr_init()
** but a new entry is only written here, so the counter can get
** "lost" if the system stops between those two functions.
** However, the startup code checks also DEFEDB for existing
** entries, hence the counter should be at least bigger than
** any counter from a previous run unless there is no data
** in either EDB in which case it is possible that IDs are
** reused which may screw up logfile analyzers...
** The race condition could be closed if another entry is written
** before the old IBDB is removed.
*/
sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, qmgr_ctx->qmgr_idc, 0);
ibdb_rcpt.ibr_ta_id = ta_id;
ibdb_rcpt.ibr_idx = 0;
ibdb_rcpt.ibr_pa = qmgr_ctx->qmgr_pm_addr;
ret = ibdb_rcpt_status(qmgr_ctx->qmgr_ibdb, &ibdb_rcpt, IBDB_RCPT_NEW,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, ibdb_rcpt_status1=%m",
ret);
goto error;
}
ret = ibdb_rcpt_status(qmgr_ctx->qmgr_ibdb, &ibdb_rcpt, IBDB_RCPT_DONE,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, ibdb_rcpt_status2=%m",
ret);
goto error;
}
ret = ibdb_commit(qmgr_ctx->qmgr_ibdb);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, ibdb_commit=%m",
ret);
goto error;
}
NOTE(COMPETING_THREADS_NOW)
ret = qm_stli(qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, qm_stli=%m", ret);
goto error;
}
/*
** XXX Notice: on a quiet system it is not a good idea to have the
** commit thread wake up every second just to figure out that
** it got nothing to do, see also qmgr_ibdb_commit.
*/
/* initial timeout: 1s */
sleept = now;
sleept.tv_sec++;
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &qmgr_ctx->qmgr_icommit,
EVTHR_EV_SL, INVALID_FD, &sleept, qmgr_ibdb_commit, qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, start_qmgr_ibdb_commit=%m", ret);
goto error;
}
sleept = now;
/* initial timeout: 10s */
delay.tv_usec = 0;
delay.tv_sec = 10;
timeradd(&now, &delay, &(sleept));
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &qmgr_ctx->qmgr_sched,
EVTHR_EV_SL, INVALID_FD, &sleept, qmgr_sched, qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, start_qmgr_sched=%m", ret);
goto error;
}
sleept = now;
sleept.tv_sec += 60;
ret = qcleanup_ctx_new(qmgr_ctx, &qmgr_ctx->qmgr_cleanup_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, qcleanup_ctx_new=%m", ret);
goto error;
}
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx,
&qmgr_ctx->qmgr_tsk_cleanup, EVTHR_EV_SL, INVALID_FD,
&sleept, qmgr_cleanup, qmgr_ctx->qmgr_cleanup_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, start_qmgr_cleanup=%m", ret);
goto error;
}
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_SG,
SIGUSR1, NULL, qm_usr1, (void *) qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, start_sm_qm_usr1=%m", ret);
goto error;
}
ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_SG,
SIGUSR2, NULL, qm_usr2, (void *) qmgr_ctx);
if (sm_is_err(ret)) {
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_INIT, QM_LMOD_START,
SM_LOG_ERR, 2,
"sev=ERROR, func=qmgr_start, start_sm_qm_usr2=%m", ret);
goto error;
}
#if QMGR_TEST
delay.tv_usec = 0;
delay.tv_sec = 1;
timeradd(&now, &delay, &sleept);
(void) evthr_new_sl(qmgr_ctx->qmgr_sched, sleept, false);
#endif /* QMGR_TEST */
qmgr_ctx->qmgr_status = QMGR_ST_START;
return SM_SUCCESS;
error:
/*
** cleanup? tasks may have been started, but QMGR will terminate
** due to the errors.
*/
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1