[MEDIUM] config: split parser and checker in two functions

This is a first step towards support of multiple configuration files.
Now readcfgfile() only reads a file in memory and performs very minimal
parsing. The checks are performed afterwards.
(cherry picked from commit 915e1ebe63)
This commit is contained in:
Willy Tarreau 2009-06-22 15:48:36 +02:00
parent e7345f355d
commit b2bec3ad3d
5 changed files with 72 additions and 62 deletions

View File

@ -64,6 +64,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv);
int readcfgfile(const char *file); int readcfgfile(const char *file);
void cfg_register_keywords(struct cfg_kw_list *kwl); void cfg_register_keywords(struct cfg_kw_list *kwl);
void cfg_unregister_keywords(struct cfg_kw_list *kwl); void cfg_unregister_keywords(struct cfg_kw_list *kwl);
void init_default_instance();
int check_config_validity();
#endif /* _COMMON_CFGPARSE_H */ #endif /* _COMMON_CFGPARSE_H */

View File

@ -40,7 +40,7 @@ const char *proxy_cap_str(int cap);
const char *proxy_mode_str(int mode); const char *proxy_mode_str(int mode);
struct proxy *findproxy(const char *name, int mode, int cap); struct proxy *findproxy(const char *name, int mode, int cap);
struct server *findserver(const struct proxy *px, const char *name); struct server *findserver(const struct proxy *px, const char *name);
int proxy_cfg_ensure_no_http(struct proxy *curproxy, const char *file); int proxy_cfg_ensure_no_http(struct proxy *curproxy);
/* /*
* This function returns a string containing the type of the proxy in a format * This function returns a string containing the type of the proxy in a format

View File

@ -661,7 +661,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int inv)
} }
static void init_default_instance() void init_default_instance()
{ {
memset(&defproxy, 0, sizeof(defproxy)); memset(&defproxy, 0, sizeof(defproxy));
defproxy.mode = PR_MODE_TCP; defproxy.mode = PR_MODE_TCP;
@ -3163,17 +3163,11 @@ int readcfgfile(const char *file)
char thisline[LINESIZE]; char thisline[LINESIZE];
FILE *f; FILE *f;
int linenum = 0; int linenum = 0;
int cfgerr = 0;
int confsect = CFG_NONE; int confsect = CFG_NONE;
struct proxy *curproxy = NULL;
struct server *newsrv = NULL;
if ((f=fopen(file,"r")) == NULL) if ((f=fopen(file,"r")) == NULL)
return -1; return -1;
init_default_instance();
while (fgets(thisline, sizeof(thisline), f) != NULL) { while (fgets(thisline, sizeof(thisline), f) != NULL) {
int arg, inv = 0 ; int arg, inv = 0 ;
char *end; char *end;
@ -3315,6 +3309,18 @@ int readcfgfile(const char *file)
free(cursection); free(cursection);
cursection = NULL; cursection = NULL;
fclose(f); fclose(f);
return 0;
err:
free(cursection);
cursection = NULL;
return -1;
}
int check_config_validity()
{
int cfgerr = 0;
struct proxy *curproxy = NULL;
struct server *newsrv = NULL;
/* /*
* Now, check for the integrity of all that we have collected. * Now, check for the integrity of all that we have collected.
@ -3337,8 +3343,7 @@ int readcfgfile(const char *file)
} }
if ((curproxy = proxy) == NULL) { if ((curproxy = proxy) == NULL) {
Alert("parsing %s : no <listen> line. Nothing to do !\n", Alert("config : no <listen> line. Nothing to do !\n");
file);
goto err; goto err;
} }
@ -3355,54 +3360,54 @@ int readcfgfile(const char *file)
switch (curproxy->mode) { switch (curproxy->mode) {
case PR_MODE_HEALTH: case PR_MODE_HEALTH:
cfgerr += proxy_cfg_ensure_no_http(curproxy, file); cfgerr += proxy_cfg_ensure_no_http(curproxy);
if (!(curproxy->cap & PR_CAP_FE)) { if (!(curproxy->cap & PR_CAP_FE)) {
Alert("parsing %s : %s '%s' cannot be in health mode as it has no frontend capability.\n", Alert("config : %s '%s' cannot be in health mode as it has no frontend capability.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
cfgerr++; cfgerr++;
} }
if (curproxy->srv != NULL) if (curproxy->srv != NULL)
Warning("parsing %s : servers will be ignored for %s '%s'.\n", Warning("config : servers will be ignored for %s '%s'.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
break; break;
case PR_MODE_TCP: case PR_MODE_TCP:
cfgerr += proxy_cfg_ensure_no_http(curproxy, file); cfgerr += proxy_cfg_ensure_no_http(curproxy);
break; break;
case PR_MODE_HTTP: case PR_MODE_HTTP:
if ((curproxy->cookie_name != NULL) && (curproxy->srv == NULL)) { if ((curproxy->cookie_name != NULL) && (curproxy->srv == NULL)) {
Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n", Alert("config : HTTP proxy %s has a cookie but no server list !\n",
file, curproxy->id); curproxy->id);
cfgerr++; cfgerr++;
} }
break; break;
} }
if ((curproxy->cap & PR_CAP_FE) && (curproxy->listen == NULL)) { if ((curproxy->cap & PR_CAP_FE) && (curproxy->listen == NULL)) {
Alert("parsing %s : %s '%s' has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", Alert("config : %s '%s' has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
cfgerr++; cfgerr++;
} }
if ((curproxy->cap & PR_CAP_BE) && (curproxy->mode != PR_MODE_HEALTH)) { if ((curproxy->cap & PR_CAP_BE) && (curproxy->mode != PR_MODE_HEALTH)) {
if (curproxy->lbprm.algo & BE_LB_ALGO) { if (curproxy->lbprm.algo & BE_LB_ALGO) {
if (curproxy->options & PR_O_TRANSP) { if (curproxy->options & PR_O_TRANSP) {
Alert("parsing %s : %s '%s' cannot use both transparent and balance mode.\n", Alert("config : %s '%s' cannot use both transparent and balance mode.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
cfgerr++; cfgerr++;
} }
#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS #ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
else if (curproxy->srv == NULL) { else if (curproxy->srv == NULL) {
Alert("parsing %s : %s '%s' needs at least 1 server in balance mode.\n", Alert("config : %s '%s' needs at least 1 server in balance mode.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
cfgerr++; cfgerr++;
} }
#endif #endif
else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) { else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
Warning("parsing %s : dispatch address of %s '%s' will be ignored in balance mode.\n", Warning("config : dispatch address of %s '%s' will be ignored in balance mode.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
} }
else if (!(curproxy->options & (PR_O_TRANSP | PR_O_HTTP_PROXY)) && else if (!(curproxy->options & (PR_O_TRANSP | PR_O_HTTP_PROXY)) &&
@ -3418,8 +3423,8 @@ int readcfgfile(const char *file)
if ((curproxy->options & PR_O_DISABLE404) && !(curproxy->options & PR_O_HTTP_CHK)) { if ((curproxy->options & PR_O_DISABLE404) && !(curproxy->options & PR_O_HTTP_CHK)) {
curproxy->options &= ~PR_O_DISABLE404; curproxy->options &= ~PR_O_DISABLE404;
Warning("parsing %s : '%s' will be ignored for %s '%s' (requires 'option httpchk').\n", Warning("config : '%s' will be ignored for %s '%s' (requires 'option httpchk').\n",
file, "disable-on-404", proxy_type_str(curproxy), curproxy->id); "disable-on-404", proxy_type_str(curproxy), curproxy->id);
} }
/* if a default backend was specified, let's find it */ /* if a default backend was specified, let's find it */
@ -3505,11 +3510,11 @@ int readcfgfile(const char *file)
(((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) || (((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) ||
((curproxy->cap & PR_CAP_BE) && (curproxy->srv) && ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
(!curproxy->timeout.connect || !curproxy->timeout.server)))) { (!curproxy->timeout.connect || !curproxy->timeout.server)))) {
Warning("parsing %s : missing timeouts for %s '%s'.\n" Warning("config : missing timeouts for %s '%s'.\n"
" | While not properly invalid, you will certainly encounter various problems\n" " | While not properly invalid, you will certainly encounter various problems\n"
" | with such a configuration. To fix this, please ensure that all following\n" " | with such a configuration. To fix this, please ensure that all following\n"
" | timeouts are set to a non-zero value: 'client', 'connect', 'server'.\n", " | timeouts are set to a non-zero value: 'client', 'connect', 'server'.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
/* Historically, the tarpit and queue timeouts were inherited from contimeout. /* Historically, the tarpit and queue timeouts were inherited from contimeout.
@ -3604,8 +3609,8 @@ int readcfgfile(const char *file)
newsrv = curproxy->srv; newsrv = curproxy->srv;
while (newsrv != NULL) { while (newsrv != NULL) {
if ((curproxy->mode != PR_MODE_HTTP) && (newsrv->rdr_len || newsrv->cklen)) { if ((curproxy->mode != PR_MODE_HTTP) && (newsrv->rdr_len || newsrv->cklen)) {
Alert("parsing [%s:%d] : %s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n", Alert("config : %s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n",
file, linenum, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
goto err; goto err;
} }
newsrv = newsrv->next; newsrv = newsrv->next;
@ -3628,8 +3633,8 @@ int readcfgfile(const char *file)
/* minconn was not specified, so we set it to maxconn */ /* minconn was not specified, so we set it to maxconn */
newsrv->minconn = newsrv->maxconn; newsrv->minconn = newsrv->maxconn;
} else if (newsrv->minconn != newsrv->maxconn && !curproxy->fullconn) { } else if (newsrv->minconn != newsrv->maxconn && !curproxy->fullconn) {
Alert("parsing [%s:%d] : %s '%s' : fullconn is mandatory when minconn is set on a server.\n", Alert("config : %s '%s' : fullconn is mandatory when minconn is set on a server.\n",
file, linenum, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
goto err; goto err;
} }
@ -3651,8 +3656,8 @@ int readcfgfile(const char *file)
if (pname) { if (pname) {
px = findproxy(pname, curproxy->mode, PR_CAP_BE); px = findproxy(pname, curproxy->mode, PR_CAP_BE);
if (!px) { if (!px) {
Alert("parsing %s, %s '%s', server '%s': unable to find required proxy '%s' for tracking.\n", Alert("config : %s '%s', server '%s': unable to find required proxy '%s' for tracking.\n",
file, proxy_type_str(curproxy), curproxy->id, proxy_type_str(curproxy), curproxy->id,
newsrv->id, pname); newsrv->id, pname);
return -1; return -1;
} }
@ -3661,25 +3666,25 @@ int readcfgfile(const char *file)
srv = findserver(px, sname); srv = findserver(px, sname);
if (!srv) { if (!srv) {
Alert("parsing %s, %s '%s', server '%s': unable to find required server '%s' for tracking.\n", Alert("config : %s '%s', server '%s': unable to find required server '%s' for tracking.\n",
file, proxy_type_str(curproxy), curproxy->id, proxy_type_str(curproxy), curproxy->id,
newsrv->id, sname); newsrv->id, sname);
return -1; return -1;
} }
if (!(srv->state & SRV_CHECKED)) { if (!(srv->state & SRV_CHECKED)) {
Alert("parsing %s, %s '%s', server '%s': unable to use %s/%s for " Alert("config : %s '%s', server '%s': unable to use %s/%s for "
"tracing as it does not have checks enabled.\n", "tracing as it does not have checks enabled.\n",
file, proxy_type_str(curproxy), curproxy->id, proxy_type_str(curproxy), curproxy->id,
newsrv->id, px->id, srv->id); newsrv->id, px->id, srv->id);
return -1; return -1;
} }
if (curproxy != px && if (curproxy != px &&
(curproxy->options & PR_O_DISABLE404) != (px->options & PR_O_DISABLE404)) { (curproxy->options & PR_O_DISABLE404) != (px->options & PR_O_DISABLE404)) {
Alert("parsing %s, %s '%s', server '%s': unable to use %s/%s for" Alert("config : %s '%s', server '%s': unable to use %s/%s for"
"tracing: disable-on-404 option inconsistency.\n", "tracing: disable-on-404 option inconsistency.\n",
file, proxy_type_str(curproxy), curproxy->id, proxy_type_str(curproxy), curproxy->id,
newsrv->id, px->id, srv->id); newsrv->id, px->id, srv->id);
return -1; return -1;
} }
@ -3720,7 +3725,7 @@ int readcfgfile(const char *file)
} }
if (cfgerr > 0) { if (cfgerr > 0) {
Alert("Errors found in configuration file, aborting.\n"); Alert("Errors found in configuration, aborting.\n");
goto err; goto err;
} }
@ -3740,13 +3745,8 @@ int readcfgfile(const char *file)
global.last_checks |= cfg_opts2[optnum].checks; global.last_checks |= cfg_opts2[optnum].checks;
} }
free(cursection);
cursection = NULL;
return 0; return 0;
err: err:
free(cursection);
cursection = NULL;
return -1; return -1;
} }

View File

@ -529,19 +529,27 @@ void init(int argc, char **argv)
have_appsession = 0; have_appsession = 0;
global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */ global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
init_default_instance();
if (readcfgfile(cfg_cfgfile) < 0) { if (readcfgfile(cfg_cfgfile) < 0) {
Alert("Error reading configuration file : %s\n", cfg_cfgfile); Alert("Error reading configuration file : %s\n", cfg_cfgfile);
exit(1); exit(1);
} }
if (have_appsession) if (check_config_validity() < 0) {
appsession_init(); Alert("Errors found in configuration.\n");
exit(1);
}
if (global.mode & MODE_CHECK) { if (global.mode & MODE_CHECK) {
qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile); qfprintf(stdout, "Configuration file is valid\n");
exit(0); exit(0);
} }
if (have_appsession)
appsession_init();
if (start_checks() < 0) if (start_checks() < 0)
exit(1); exit(1);

View File

@ -303,29 +303,29 @@ struct server *findserver(const struct proxy *px, const char *name) {
* at the end of the configuration parsing if the proxy is not in http mode. * at the end of the configuration parsing if the proxy is not in http mode.
* The <file> argument is used to construct the error message. * The <file> argument is used to construct the error message.
*/ */
int proxy_cfg_ensure_no_http(struct proxy *curproxy, const char *file) int proxy_cfg_ensure_no_http(struct proxy *curproxy)
{ {
if (curproxy->cookie_name != NULL) { if (curproxy->cookie_name != NULL) {
Warning("parsing %s : cookie will be ignored for %s '%s' (needs 'mode http').\n", Warning("config : cookie will be ignored for %s '%s' (needs 'mode http').\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
if (curproxy->rsp_exp != NULL) { if (curproxy->rsp_exp != NULL) {
Warning("parsing %s : server regular expressions will be ignored for %s '%s' (needs 'mode http').\n", Warning("config : server regular expressions will be ignored for %s '%s' (needs 'mode http').\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
if (curproxy->req_exp != NULL) { if (curproxy->req_exp != NULL) {
Warning("parsing %s : client regular expressions will be ignored for %s '%s' (needs 'mode http').\n", Warning("config : client regular expressions will be ignored for %s '%s' (needs 'mode http').\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
if (curproxy->monitor_uri != NULL) { if (curproxy->monitor_uri != NULL) {
Warning("parsing %s : monitor-uri will be ignored for %s '%s' (needs 'mode http').\n", Warning("config : monitor-uri will be ignored for %s '%s' (needs 'mode http').\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
if (curproxy->lbprm.algo & BE_LB_PROP_L7) { if (curproxy->lbprm.algo & BE_LB_PROP_L7) {
curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo &= ~BE_LB_ALGO;
curproxy->lbprm.algo |= BE_LB_ALGO_RR; curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Warning("parsing %s : Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n", Warning("config : Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n",
file, proxy_type_str(curproxy), curproxy->id); proxy_type_str(curproxy), curproxy->id);
} }
return 0; return 0;
} }