/*
* 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_rdcf.c,v 1.103 2007/07/13 04:17:02 ca Exp $")
#include "sm/common.h"
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/ctype.h"
#define QMGR_DEBUG_DEFINE 1
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "qmgr.h"
#include "sm/rfc2821.h"
#include "sm/sysexits.h"
#include "sm/version.h"
#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"
#include "sm/limits.h"
#include "sm/qmgrcnfdef.h"
#include "sm/util.h"
/*
** QMGR_SHOWCOPT -- show compile time options
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** none
*/
static void
qmgr_showcopt(qmgr_ctx_P qmgr_ctx)
{
sm_io_fprintf(smioout, "compile time options:\n"
#if QMGR_DEBUG
"QMGR_DEBUG\n"
#endif
#if SM_DELAYED_DSN
"SM_DELAYED_DSN\n"
#endif
#if QMGR_STATS
"QMGR_STATS\n"
#endif
#if QMGR_TEST
"QMGR_TEST\n"
#endif
#if QMGR_TEST_NO_AQUPDATE
"QMGR_TEST_NO_AQUPDATE\n"
#endif
#if RCBCOMM_DEBUG
"RCBCOMM_DEBUG\n"
#endif
);
(void) evthr_comptoptions(NULL, smioout);
}
/*
** QMGR_SHOWVERSION -- show version information
**
** Parameters:
** qmgr_ctx -- QMGR context
** progname -- program name
** cnf -- configuration file name
** level -- how much detail?
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
qmgr_showversion(qmgr_ctx_P qmgr_ctx, const char *progname, const char *cnf, uint level)
{
char *prefix;
prefix = "";
if (level >= SM_SV_RD_CONF)
prefix = "# ";
sm_io_fprintf(smioout, "%s%s: %s\n", prefix, progname, MTA_VERSION_STR);
if (SM_SHOW_VERSION(level))
sm_io_fprintf(smioout, "%sversion=0x%08x\n",
prefix, MTA_VERSION);
if (SM_SHOW_LIBS(level))
(void) sm_bdbversionprt(smioout);
if (SM_SHOW_OPTIONS(level))
(void) qmgr_showcopt(qmgr_ctx);
if (SM_SHOW_RD_CONF(level) && cnf != NULL && *cnf != '\0') {
sm_io_fprintf(smioout, "# configuration-file=%s\n\n", cnf);
(void) sm_conf_prt_conf(qmgr_global_defs, &qmgr_ctx->qmgr_cnf, smioout);
}
else if (SM_SHOW_DFLT_CONF(level)) {
sm_io_fprintf(smioout, "# default configuration:\n\n");
(void) sm_conf_prt_dflt(qmgr_global_defs, 0, smioout);
}
else if (SM_SHOW_ALL_CONF(level)) {
sm_io_fprintf(smioout,
"# configuration including flags.\n"
"# note: this data cannot be used as configuration file\n"
"# but it shows the available flags.\n"
);
(void) sm_conf_prt_dflt(qmgr_global_defs, SMC_FLD_FLAGS, smioout);
}
sm_io_flush(smioout);
return sm_error_perm(SM_EM_Q_START, SM_E_DONTSTART);
}
/*
** QMGR_USAGE -- Print QMGR usage message to smioerr
**
** Parameters:
** qmgr_ctx -- QMGR context
**
** Returns:
** sm_error_perm(SM_EM_Q, SM_E_USAGE)
**
** Last code review: 2003-10-17 16:10:54
*/
static sm_ret_T
qmgr_usage(qmgr_ctx_P qmgr_ctx)
{
sm_io_fprintf(smioerr, "usage: qmgr [options]\n"
"%s queue manager\n"
"-A n AQ size [%u] (must be at least 32)\n"
"-B n IBDB size (KB) [%u] (must be at least 32)\n"
"-C n Maximum number of concurrent connections to one IP addr [%d]\n"
"-c n Initial number of concurrent connections to one IP addr [%d]\n"
"-D s Initial delay for retries [%us]\n"
#if QMGR_DEBUG
"-d n Debug level\n"
#endif
#if EVTHR_DEBUG
"-e n Evthr debug level\n"
#endif
"-F n Configuration flags\n"
"-f name Name of configuration file [none]\n"
"-I n IQDB rsc size [%u] (must be at least 32)\n"
#if SM_HEAP_CHECK
"-H n Set heap check level\n"
#endif
"-M s Maximum delay for retries [%us] (must be greater than -D)\n"
"-O H=n IQDB hash table size (should be larger than rsc size) [%u]\n"
" (must be at least 128)\n"
"-O D=n Maximum number of bounce messages in a DSN [%d]\n"
"-O O=n Maximum number of open connections (SMTPS) [%d]\n"
" (must be at least 10)\n"
"-O R=n Maximum connection rate per 60s (SMTPS) [%d]\n"
"-O T=n Maximum number of open IBDB transactions [%d]\n"
"-O m=n Minimum free disk space (KB) [%d]\n"
"-O o=n ok free disk space (KB) [%d]\n"
"-P address Postmaster address for double bounces (must be in <>)\n"
"-s n Maximum time before scheduling a DSN [%us] (must be at least 1)\n"
"-S a=name Socket for communication with SMAR [%s]\n"
"-S c=name Socket for communication with SMTP clients [%s]\n"
"-S C=name Directory for CDB [%s]\n"
"-S s=name Socket for communication with SMTP servers [%s]\n"
#if QMGR_TEST
"-t n Set test flags\n"
#endif
"-T n Maximum time in queue [%us] (must be at least 2)\n"
"-T a=n Maximum time in AR [%us]\n"
"-T d=n Maximum time in DA [%us]\n"
"-T D=n Initial delay for retries [%us]\n"
"-T i=n Maximum time to acknowledge an IBDB transaction [%dmicro s]\n"
"-T M=n Maximum delay for retries [%us]\n"
"-T w=n send delay warning after this time in queue [%us] (>= 2)\n"
"-T R=n Maximum time in queue [%us] (must be at least 2)\n"
"-v n Set loglevel\n"
"-V Show version\n"
"-w n Time to wait for SMAR to be ready (must be at least 1)\n"
"-W n Time to wait for SMTPC to be ready (must be at least 1)\n"
#if QMGR_DEBUG
"-x dbg.n Set debug level to n for category dbg\n"
#endif
, MTA_VERSION_STR
, AQ_SIZE /* -A */
, IBDB_SIZE / 1024 /* -B */
, DA_MAX_CONC_CONN /* -C */
, DA_INIT_CONC_CONN /* -c */
, MIN_DELAY_NXT_TRY /* -D */
, IQDB_CSIZE /* -I */
, MAX_DELAY_NXT_TRY /* -M */
, IQDB_HTSIZE /* -O H */
, AQR_DSN_RCPTS_MAX /* -O D */
, SS_MAX_CONN_RATE /* -O O */
, SS_MAX_OPEN_SE /* -O R */
, IBDB_OPEN_TAS /* -O T */
, DISK_MIN_FREE /* -O m */
, DISK_OK_FREE /* -O o */
, QM_TMO_SCHED_DSN /* -s */
, qmgr_ctx->qmgr_cnf.q_cnf_smarsock /* -S a */
, qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock /* -S c */
, qmgr_ctx->qmgr_cnf.q_cnf_cdb_base /* -S C */
, qmgr_ctx->qmgr_cnf.q_cnf_smtpssock /* -S s */
, QM_TMO_RETURN /* -T */
, AQR_AR_TMOUT /* -T a */
, AQR_DA_TMOUT /* -T d */
, MIN_DELAY_NXT_TRY /* -T D */
, IBDB_DELAY /* -T i */
, MAX_DELAY_NXT_TRY /* -T M */
, QM_TMO_DELAY /* -T w */
, QM_TMO_RETURN /* -T R */
);
return sm_error_perm(SM_EM_Q, SM_E_USAGE);
}
/*
** QMGR_RDCF -- read configuration
**
** Parameters:
** qmgr_ctx -- QMGR context
** argc -- number of arguments
** argv -- vector of arguments
**
** Returns:
** usual sm_error code
**
** Last code review: 2003-10-17 16:11:18
*/
sm_ret_T
qmgr_rdcf(qmgr_ctx_P qmgr_ctx, int argc, char *argv[])
{
sm_ret_T ret, rv;
int c, off;
uint u, j, showversion;
char *s;
SM_IS_QMGR_CTX(qmgr_ctx);
ret = SM_SUCCESS;
showversion = 0;
while ((c = getopt(argc, argv,
"?A:B:C:c:D:d:e:F:f:H:hI:M:O:P:s:S:t:T:v:Vw:W:x:")) != -1)
{
switch (c)
{
case 'A':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 32)
qmgr_ctx->qmgr_cnf.q_cnf_aq_size = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'B':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 32)
qmgr_ctx->qmgr_cnf.q_cnf_ibdb_size = u * 1024;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'C':
qmgr_ctx->qmgr_cnf.q_cnf_max_conc_conn=
(uint) strtoul(optarg, NULL, 0);
break;
case 'c':
qmgr_ctx->qmgr_cnf.q_cnf_init_conc_conn =
(uint) strtoul(optarg, NULL, 0);
break;
case 'D':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 0)
qmgr_ctx->qmgr_cnf.q_cnf_min_delay = u * 2;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'd':
j = (uint) strtoul(optarg, NULL, 0);
#if QMGR_DEBUG
for (u = 0; u < SM_ARRAY_SIZE(qm_debug); u++)
qm_debug[u] = j;
#endif
#if RCBCOMM_DEBUG
rcbcomm_debug = j;
#endif
break;
case 'e':
#if EVTHR_DEBUG
qmgr_ctx->qmgr_evthr_dbg_lvl = (uint) strtoul(optarg, NULL, 0);
#endif
break;
case 'F':
u = (uint) strtoul(optarg, NULL, 0);
qmgr_ctx->qmgr_cnf.q_cnf_flags = u;
break;
case 'f':
s = strdup(optarg);
if (NULL == s) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, argument=\"%@s\", strdup=%m\n"
, optarg, sm_err_temp(errno));
ret = sm_error_perm(SM_EM_Q_START, EX_OSERR);
break;
}
qmgr_ctx->qmgr_cnf.q_cnf_conffile = s;
ret = qm_read_cnf(qmgr_ctx, s, &qmgr_ctx->qmgr_cnf.q_cnf_smc);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, status=invalid_configuration_file, error=%m\n"
, ret);
}
break;
case 'H':
#if 0
u = (uint) strtoul(optarg, NULL, 0);
if (u > 128)
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_htsize = u;
else
ret = qmgr_usage(qmgr_ctx);
#endif /* 0 */
#if SM_HEAP_CHECK
SmHeapCheck = strtoul(optarg, NULL, 0);
#endif
break;
case 'I':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 32)
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_csize = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'M':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 0 && u > qmgr_ctx->qmgr_cnf.q_cnf_min_delay)
qmgr_ctx->qmgr_cnf.q_cnf_max_delay = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'O':
if (optarg != NULL && ISALPHA(optarg[0])
&& optarg[1] == '=')
off = 2;
else
off = 0;
u = (uint) strtoul(optarg + off, NULL, 0);
if (off > 0) {
switch (optarg[0])
{
case 'H':
if (u > 128)
qmgr_ctx->qmgr_cnf.q_cnf_iqdb_htsize = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'D':
qmgr_ctx->qmgr_cnf.q_cnf_dsn_rcpts_max = u;
break;
case 'm':
if (u > 1000)
qmgr_ctx->qmgr_cnf.q_cnf_min_df = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'o':
if (u > 1000 &&
u > qmgr_ctx->qmgr_cnf.q_cnf_min_df)
qmgr_ctx->qmgr_cnf.q_cnf_ok_df = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'R':
qmgr_ctx->qmgr_cnf.q_cnf_max_conn_rate = u;
break;
case 'T':
qmgr_ctx->qmgr_cnf.q_cnf_optas = u;
break;
case 'O':
default:
qmgr_ctx->qmgr_cnf.q_cnf_max_open_se = u;
break;
}
}
else
qmgr_ctx->qmgr_cnf.q_cnf_max_open_se = u;
break;
case 'P':
qmgr_ctx->qmgr_pm_addr = sm_str_scpy0(NULL, optarg, MAXADDRLEN);
if (NULL == qmgr_ctx->qmgr_pm_addr) {
ret = sm_error_temp(SM_EM_Q, ENOMEM);
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, status=cannot copy postmaster address, error=Cannot allocate memory\n");
break;
}
else {
sm_a2821_T addr;
A2821_INIT_RP(&addr, NULL);
rv = t2821_scan((sm_rdstr_P) qmgr_ctx->qmgr_pm_addr, &addr, 0);
if (!sm_is_err(rv))
rv = t2821_parse(&addr, R2821_CORRECT|R2821_EMPTY);
if (sm_is_err(rv)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, address=\"%@s\", status=invalid, parse=%m\n",
optarg, ret);
SM_STR_FREE(qmgr_ctx->qmgr_pm_addr);
ret = rv;
}
(void) a2821_free(&addr);
}
break;
case 's':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 1)
qmgr_ctx->qmgr_cnf.q_cnf_t_sched_dsn = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'S':
if (optarg != NULL && ISALPHA(optarg[0])
&& optarg[1] == '=' && optarg[2] != '\0')
off = 2;
else {
ret = qmgr_usage(qmgr_ctx);
break;
}
s = NULL;
switch (optarg[0])
{
case 'a':
case 'c':
case 'C':
case 's':
s = strdup(optarg + off);
if (NULL == s) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, argument=\"%@s\", strdup=%m\n"
, optarg + off
, sm_err_temp(errno));
ret = sm_error_perm(SM_EM_Q_START, EX_OSERR);
}
break;
default:
ret = qmgr_usage(qmgr_ctx);
break;
}
switch (optarg[0])
{
case 'a':
qmgr_ctx->qmgr_cnf.q_cnf_smarsock = s;
break;
case 'c':
qmgr_ctx->qmgr_cnf.q_cnf_smtpcsock = s;
break;
case 'C':
qmgr_ctx->qmgr_cnf.q_cnf_cdb_base = s;
break;
case 's':
qmgr_ctx->qmgr_cnf.q_cnf_smtpssock = s;
break;
default:
ret = qmgr_usage(qmgr_ctx);
break;
}
s = NULL;
break;
case 't':
#if QMGR_TEST
u = (uint) strtoul(optarg, NULL, 0);
qmgr_ctx->qmgr_cnf.q_cnf_tests = u;
#endif
break;
case 'T':
if (optarg != NULL && ISALPHA(optarg[0]) && optarg[1] == '=')
off = 2;
else
off = 0;
u = (uint) strtoul(optarg + off, NULL, 0);
if (u > 1) {
if (off > 0) {
switch (optarg[0])
{
case 'a':
qmgr_ctx->qmgr_cnf.q_cnf_tmo_ar = u;
break;
case 'd':
qmgr_ctx->qmgr_cnf.q_cnf_tmo_da = u;
break;
case 'D':
qmgr_ctx->qmgr_cnf.q_cnf_min_delay = u;
break;
case 'i':
if (u > 10)
qmgr_ctx->qmgr_cnf.q_cnf_ibdb_delay = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'M':
qmgr_ctx->qmgr_cnf.q_cnf_max_delay = u;
break;
case 'w':
qmgr_ctx->qmgr_cnf.q_cnf_tmo_delay = u;
break;
case 'R':
default:
qmgr_ctx->qmgr_cnf.q_cnf_tmo_return = u;
break;
}
}
else
qmgr_ctx->qmgr_cnf.q_cnf_tmo_return = u;
}
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'v':
qmgr_ctx->qmgr_cnf.q_cnf_loglevel =
(uint) strtoul(optarg, NULL, 0);
break;
case 'V':
++showversion;
break;
case 'w':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 0)
qmgr_ctx->qmgr_cnf.q_cnf_wait4srv = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'W':
u = (uint) strtoul(optarg, NULL, 0);
if (u > 0)
qmgr_ctx->qmgr_cnf.q_cnf_wait4clt = u;
else
ret = qmgr_usage(qmgr_ctx);
break;
case 'x':
#if QMGR_DEBUG
s = optarg;
rv = sm_set_dbgcats(&s, qm_debug, SM_ARRAY_SIZE(qm_debug));
if (sm_is_err(rv))
ret = rv;
#endif
break;
case 'h':
case '?':
default:
ret = qmgr_usage(qmgr_ctx);
break;
}
}
if (showversion > 0) {
ret = qmgr_showversion(qmgr_ctx, argv[0],
qmgr_ctx->qmgr_cnf.q_cnf_conffile, showversion);
}
if (sm_is_success(ret)) {
/* more plausibility checks? */
if (qmgr_ctx->qmgr_cnf.q_cnf_min_df >= qmgr_ctx->qmgr_cnf.q_cnf_ok_df)
{
sm_io_fprintf(smioerr,
"sev=ERROR, func=qmgr_rdcf, "
"minimum_free_disk_space=%d, "
"ok_free_disk_space=%d, "
"status=misconfigured\n"
, qmgr_ctx->qmgr_cnf.q_cnf_min_df
, qmgr_ctx->qmgr_cnf.q_cnf_ok_df
);
ret = qmgr_usage(qmgr_ctx);
}
else
qmgr_ctx->qmgr_status = QMGR_ST_CONF;
if (qmgr_ctx->qmgr_cnf.q_cnf_conffile != NULL)
qmgr_prt_cnf(&qmgr_ctx->qmgr_cnf, smioerr, true);
}
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1