MEDIUM: cfgparse: use the new error reporting framework for remaining cfg_keywords

All keywords registered using a cfg_kw_list now make use of the new error reporting
framework. This allows easier and more precise error reporting without having to
deal with complex buffer allocation issues.
This commit is contained in:
Willy Tarreau 2012-05-08 19:47:01 +02:00
parent a93c74be5c
commit 0a3dd74c9c
7 changed files with 194 additions and 199 deletions

View File

@ -1,23 +1,23 @@
/* /*
include/common/cfgparse.h * include/common/cfgparse.h
Configuration parsing functions. * Configuration parsing functions.
*
Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu * Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu
*
This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, version 2.1 * License as published by the Free Software Foundation, version 2.1
exclusively. * exclusively.
*
This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. * Lesser General Public License for more details.
*
You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _COMMON_CFGPARSE_H #ifndef _COMMON_CFGPARSE_H
#define _COMMON_CFGPARSE_H #define _COMMON_CFGPARSE_H
@ -43,8 +43,7 @@ struct cfg_keyword {
int section_type, /* current section CFG_{GLOBAL|LISTEN} */ int section_type, /* current section CFG_{GLOBAL|LISTEN} */
struct proxy *curpx, /* current proxy (NULL in GLOBAL) */ struct proxy *curpx, /* current proxy (NULL in GLOBAL) */
struct proxy *defpx, /* default proxy (NULL in GLOBAL) */ struct proxy *defpx, /* default proxy (NULL in GLOBAL) */
char *err, /* error message buffer (do not add '\n') */ char **err); /* error or warning message output pointer */
int errlen); /* error buffer size, '\0' included */
}; };
/* A keyword list. It is a NULL-terminated array of keywords. It embeds a /* A keyword list. It is a NULL-terminated array of keywords. It embeds a

View File

@ -46,7 +46,7 @@ void default_srv_error(struct session *s, struct stream_interface *si);
int parse_track_counters(char **args, int *arg, int parse_track_counters(char **args, int *arg,
int section_type, struct proxy *curpx, int section_type, struct proxy *curpx,
struct track_ctr_prm *prm, struct track_ctr_prm *prm,
struct proxy *defpx, char *err, int errlen); struct proxy *defpx, char **err);
/* Remove the refcount from the session to the tracked counters, and clear the /* Remove the refcount from the session to the tracked counters, and clear the
* pointer to ensure this is only performed once. The caller is responsible for * pointer to ensure this is only performed once. The caller is responsible for

View File

@ -454,6 +454,7 @@ static int warnif_cond_requires_req(const struct acl_cond *cond, const char *fil
int cfg_parse_global(const char *file, int linenum, char **args, int kwm) int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
{ {
int err_code = 0; int err_code = 0;
char *errmsg = NULL;
if (!strcmp(args[0], "global")) { /* new section */ if (!strcmp(args[0], "global")) { /* new section */
/* no option, nothing special to do */ /* no option, nothing special to do */
@ -1032,13 +1033,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
/* prepare error message just in case */ /* prepare error message just in case */
snprintf(trash, sizeof(trash), snprintf(trash, sizeof(trash),
"error near '%s' in '%s' section", args[0], "global"); "error near '%s' in '%s' section", args[0], "global");
rc = kwl->kw[index].parse(args, CFG_GLOBAL, NULL, NULL, trash, sizeof(trash)); rc = kwl->kw[index].parse(args, CFG_GLOBAL, NULL, NULL, &errmsg);
if (rc < 0) { if (rc < 0) {
Alert("parsing [%s:%d] : %s\n", file, linenum, trash); Alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
} }
else if (rc > 0) { else if (rc > 0) {
Warning("parsing [%s:%d] : %s\n", file, linenum, trash); Warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
err_code |= ERR_WARN; err_code |= ERR_WARN;
goto out; goto out;
} }
@ -1052,6 +1053,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
} }
out: out:
free(errmsg);
return err_code; return err_code;
} }
@ -5249,14 +5251,14 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
/* prepare error message just in case */ /* prepare error message just in case */
snprintf(trash, sizeof(trash), snprintf(trash, sizeof(trash),
"error near '%s' in %s section", args[0], cursection); "error near '%s' in %s section", args[0], cursection);
rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, trash, sizeof(trash)); rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, &errmsg);
if (rc < 0) { if (rc < 0) {
Alert("parsing [%s:%d] : %s\n", file, linenum, trash); Alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
else if (rc > 0) { else if (rc > 0) {
Warning("parsing [%s:%d] : %s\n", file, linenum, trash); Warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
err_code |= ERR_WARN; err_code |= ERR_WARN;
goto out; goto out;
} }

View File

@ -170,39 +170,38 @@ static struct proxy *alloc_stats_fe(const char *name)
} }
/* This function parses a "stats" statement in the "global" section. It returns /* This function parses a "stats" statement in the "global" section. It returns
* -1 if there is any error, otherwise zero. If it returns -1, it may write an * -1 if there is any error, otherwise zero. If it returns -1, it will write an
* error message into ther <err> buffer, for at most <errlen> bytes, trailing * error message into the <err> buffer which will be preallocated. The trailing
* zero included. The trailing '\n' must not be written. The function must be * '\n' must not be written. The function must be called with <args> pointing to
* called with <args> pointing to the first word after "stats". * the first word after "stats".
*/ */
static int stats_parse_global(char **args, int section_type, struct proxy *curpx, static int stats_parse_global(char **args, int section_type, struct proxy *curpx,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
args++; if (!strcmp(args[1], "socket")) {
if (!strcmp(args[0], "socket")) {
struct sockaddr_un *su; struct sockaddr_un *su;
int cur_arg; int cur_arg;
if (*args[1] == 0) { if (*args[2] == 0) {
snprintf(err, errlen, "'stats socket' in global section expects a path to a UNIX socket"); memprintf(err, "'%s %s' in global section expects a path to a UNIX socket", args[0], args[1]);
return -1; return -1;
} }
if (global.stats_sock.state != LI_NEW) { if (global.stats_sock.state != LI_NEW) {
snprintf(err, errlen, "'stats socket' already specified in global section"); memprintf(err, "'%s %s' already specified in global section", args[0], args[1]);
return -1; return -1;
} }
su = str2sun(args[1]); su = str2sun(args[2]);
if (!su) { if (!su) {
snprintf(err, errlen, "'stats socket' path would require truncation"); memprintf(err, "'%s %s' : path would require truncation", args[0], args[1]);
return -1; return -1;
} }
memcpy(&global.stats_sock.addr, su, sizeof(struct sockaddr_un)); // guaranteed to fit memcpy(&global.stats_sock.addr, su, sizeof(struct sockaddr_un)); // guaranteed to fit
if (!global.stats_fe) { if (!global.stats_fe) {
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) { if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
snprintf(err, errlen, "out of memory"); memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
return -1; return -1;
} }
} }
@ -222,7 +221,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
global.stats_sock.next = global.stats_fe->listen; global.stats_sock.next = global.stats_fe->listen;
global.stats_fe->listen = &global.stats_sock; global.stats_fe->listen = &global.stats_sock;
cur_arg = 2; cur_arg = 3;
while (*args[cur_arg]) { while (*args[cur_arg]) {
if (!strcmp(args[cur_arg], "uid")) { if (!strcmp(args[cur_arg], "uid")) {
global.stats_sock.perm.ux.uid = atol(args[cur_arg + 1]); global.stats_sock.perm.ux.uid = atol(args[cur_arg + 1]);
@ -240,8 +239,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
struct passwd *user; struct passwd *user;
user = getpwnam(args[cur_arg + 1]); user = getpwnam(args[cur_arg + 1]);
if (!user) { if (!user) {
snprintf(err, errlen, "unknown user '%s' in 'global' section ('stats user')", memprintf(err, "'%s %s' : unknown user '%s'", args[0], args[1], args[cur_arg + 1]);
args[cur_arg + 1]);
return -1; return -1;
} }
global.stats_sock.perm.ux.uid = user->pw_uid; global.stats_sock.perm.ux.uid = user->pw_uid;
@ -251,8 +249,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
struct group *group; struct group *group;
group = getgrnam(args[cur_arg + 1]); group = getgrnam(args[cur_arg + 1]);
if (!group) { if (!group) {
snprintf(err, errlen, "unknown group '%s' in 'global' section ('stats group')", memprintf(err, "'%s %s' : unknown group '%s'", args[0], args[1], args[cur_arg + 1]);
args[cur_arg + 1]);
return -1; return -1;
} }
global.stats_sock.perm.ux.gid = group->gr_gid; global.stats_sock.perm.ux.gid = group->gr_gid;
@ -266,13 +263,15 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
else if (!strcmp(args[cur_arg+1], "admin")) else if (!strcmp(args[cur_arg+1], "admin"))
global.stats_sock.perm.ux.level = ACCESS_LVL_ADMIN; global.stats_sock.perm.ux.level = ACCESS_LVL_ADMIN;
else { else {
snprintf(err, errlen, "'stats socket level' only supports 'user', 'operator', and 'admin'"); memprintf(err, "'%s %s' : '%s' only supports 'user', 'operator', and 'admin' (got '%s')",
args[0], args[1], args[cur_arg], args[cur_arg+1]);
return -1; return -1;
} }
cur_arg += 2; cur_arg += 2;
} }
else { else {
snprintf(err, errlen, "'stats socket' only supports 'user', 'uid', 'group', 'gid', 'level', and 'mode'"); memprintf(err, "'%s %s' only supports 'user', 'uid', 'group', 'gid', 'level', and 'mode' (got '%s')",
args[0], args[1], args[cur_arg]);
return -1; return -1;
} }
} }
@ -280,45 +279,45 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
uxst_add_listener(&global.stats_sock); uxst_add_listener(&global.stats_sock);
global.maxsock++; global.maxsock++;
} }
else if (!strcmp(args[0], "timeout")) { else if (!strcmp(args[1], "timeout")) {
unsigned timeout; unsigned timeout;
const char *res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); const char *res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
if (res) { if (res) {
snprintf(err, errlen, "unexpected character '%c' in 'stats timeout' in 'global' section", *res); memprintf(err, "'%s %s' : unexpected character '%c'", args[0], args[1], *res);
return -1; return -1;
} }
if (!timeout) { if (!timeout) {
snprintf(err, errlen, "a positive value is expected for 'stats timeout' in 'global section'"); memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
return -1; return -1;
} }
if (!global.stats_fe) { if (!global.stats_fe) {
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) { if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
snprintf(err, errlen, "out of memory"); memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
return -1; return -1;
} }
} }
global.stats_fe->timeout.client = MS_TO_TICKS(timeout); global.stats_fe->timeout.client = MS_TO_TICKS(timeout);
} }
else if (!strcmp(args[0], "maxconn")) { else if (!strcmp(args[1], "maxconn")) {
int maxconn = atol(args[1]); int maxconn = atol(args[2]);
if (maxconn <= 0) { if (maxconn <= 0) {
snprintf(err, errlen, "a positive value is expected for 'stats maxconn' in 'global section'"); memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
return -1; return -1;
} }
if (!global.stats_fe) { if (!global.stats_fe) {
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) { if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
snprintf(err, errlen, "out of memory"); memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
return -1; return -1;
} }
} }
global.stats_fe->maxconn = maxconn; global.stats_fe->maxconn = maxconn;
} }
else { else {
snprintf(err, errlen, "'stats' only supports 'socket', 'maxconn' and 'timeout' in 'global' section"); memprintf(err, "'%s' only supports 'socket', 'maxconn' and 'timeout' (got '%s')", args[0], args[1]);
return -1; return -1;
} }
return 0; return 0;

View File

@ -936,11 +936,11 @@ int tcp_exec_req_rules(struct session *s)
/* Parse a tcp-response rule. Return a negative value in case of failure */ /* Parse a tcp-response rule. Return a negative value in case of failure */
static int tcp_parse_response_rule(char **args, int arg, int section_type, static int tcp_parse_response_rule(char **args, int arg, int section_type,
struct proxy *curpx, struct proxy *defpx, struct proxy *curpx, struct proxy *defpx,
struct tcp_rule *rule, char *err, int errlen) struct tcp_rule *rule, char **err)
{ {
if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) { if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
snprintf(err, errlen, "%s %s is only allowed in 'backend' sections", memprintf(err, "%s %s is only allowed in 'backend' sections",
args[0], args[1]); args[0], args[1]);
return -1; return -1;
} }
@ -953,26 +953,23 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
rule->action = TCP_ACT_REJECT; rule->action = TCP_ACT_REJECT;
} }
else { else {
snprintf(err, errlen, memprintf(err,
"'%s %s' expects 'accept' or 'reject' in %s '%s' (was '%s')", "'%s %s' expects 'accept' or 'reject' in %s '%s' (got '%s')",
args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
return -1; return -1;
} }
if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
char *errmsg = NULL; if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, err)) == NULL) {
memprintf(err,
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) { "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s",
snprintf(err, errlen, args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err);
"error detected in %s '%s' while parsing '%s' condition : %s",
proxy_type_str(curpx), curpx->id, args[arg], errmsg);
free(errmsg);
return -1; return -1;
} }
} }
else if (*args[arg]) { else if (*args[arg]) {
snprintf(err, errlen, memprintf(err,
"'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')", "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (got '%s')",
args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]); args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
return -1; return -1;
} }
@ -984,11 +981,11 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
/* Parse a tcp-request rule. Return a negative value in case of failure */ /* Parse a tcp-request rule. Return a negative value in case of failure */
static int tcp_parse_request_rule(char **args, int arg, int section_type, static int tcp_parse_request_rule(char **args, int arg, int section_type,
struct proxy *curpx, struct proxy *defpx, struct proxy *curpx, struct proxy *defpx,
struct tcp_rule *rule, char *err, int errlen) struct tcp_rule *rule, char **err)
{ {
if (curpx == defpx) { if (curpx == defpx) {
snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections", memprintf(err, "%s %s is not allowed in 'defaults' sections",
args[0], args[1]); args[0], args[1]);
return -1; return -1;
} }
@ -1002,50 +999,55 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
} }
else if (strcmp(args[arg], "track-sc1") == 0) { else if (strcmp(args[arg], "track-sc1") == 0) {
int ret; int ret;
int kw = arg;
arg++; arg++;
ret = parse_track_counters(args, &arg, section_type, curpx, ret = parse_track_counters(args, &arg, section_type, curpx,
&rule->act_prm.trk_ctr, defpx, err, errlen); &rule->act_prm.trk_ctr, defpx, err);
if (ret < 0) /* nb: warnings are not handled yet */
return -1;
if (ret < 0) { /* nb: warnings are not handled yet */
memprintf(err,
"'%s %s %s' : %s in %s '%s'",
args[0], args[1], args[kw], *err, proxy_type_str(curpx), curpx->id);
return ret;
}
rule->action = TCP_ACT_TRK_SC1; rule->action = TCP_ACT_TRK_SC1;
} }
else if (strcmp(args[arg], "track-sc2") == 0) { else if (strcmp(args[arg], "track-sc2") == 0) {
int ret; int ret;
int kw = arg;
arg++; arg++;
ret = parse_track_counters(args, &arg, section_type, curpx, ret = parse_track_counters(args, &arg, section_type, curpx,
&rule->act_prm.trk_ctr, defpx, err, errlen); &rule->act_prm.trk_ctr, defpx, err);
if (ret < 0) /* nb: warnings are not handled yet */
return -1;
if (ret < 0) { /* nb: warnings are not handled yet */
memprintf(err,
"'%s %s %s' : %s in %s '%s'",
args[0], args[1], args[kw], *err, proxy_type_str(curpx), curpx->id);
return ret;
}
rule->action = TCP_ACT_TRK_SC2; rule->action = TCP_ACT_TRK_SC2;
} }
else { else {
snprintf(err, errlen, memprintf(err,
"'%s %s' expects 'accept', 'reject', 'track-sc1' " "'%s %s' expects 'accept', 'reject', 'track-sc1' "
"or 'track-sc2' in %s '%s' (was '%s')", "or 'track-sc2' in %s '%s' (got '%s')",
args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
return -1; return -1;
} }
if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
char *errmsg = NULL; if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, err)) == NULL) {
memprintf(err,
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) { "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s",
snprintf(err, errlen, args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err);
"error detected in %s '%s' while parsing '%s' condition : %s",
proxy_type_str(curpx), curpx->id, args[arg], errmsg);
free(errmsg);
return -1; return -1;
} }
} }
else if (*args[arg]) { else if (*args[arg]) {
snprintf(err, errlen, memprintf(err,
"'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')", "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (got '%s')",
args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]); args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
return -1; return -1;
} }
@ -1056,41 +1058,39 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
* keyword. * keyword.
*/ */
static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx, static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
const char *ptr = NULL; const char *ptr = NULL;
unsigned int val; unsigned int val;
int retlen;
int warn = 0; int warn = 0;
int arg; int arg;
struct tcp_rule *rule; struct tcp_rule *rule;
if (!*args[1]) { if (!*args[1]) {
snprintf(err, errlen, "missing argument for '%s' in %s '%s'", memprintf(err, "missing argument for '%s' in %s '%s'",
args[0], proxy_type_str(curpx), curpx->id); args[0], proxy_type_str(curpx), curpx->id);
return -1; return -1;
} }
if (strcmp(args[1], "inspect-delay") == 0) { if (strcmp(args[1], "inspect-delay") == 0) {
if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) { if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
snprintf(err, errlen, "%s %s is only allowed in 'backend' sections", memprintf(err, "%s %s is only allowed in 'backend' sections",
args[0], args[1]); args[0], args[1]);
return -1; return -1;
} }
if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) { if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
retlen = snprintf(err, errlen, memprintf(err,
"'%s %s' expects a positive delay in milliseconds, in %s '%s'", "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
args[0], args[1], proxy_type_str(curpx), curpx->id); args[0], args[1], proxy_type_str(curpx), curpx->id);
if (ptr && retlen < errlen) if (ptr)
retlen += snprintf(err + retlen, errlen - retlen, memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
" (unexpected character '%c')", *ptr);
return -1; return -1;
} }
if (curpx->tcp_rep.inspect_delay) { if (curpx->tcp_rep.inspect_delay) {
snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'", memprintf(err, "ignoring %s %s (was already defined) in %s '%s'",
args[0], args[1], proxy_type_str(curpx), curpx->id); args[0], args[1], proxy_type_str(curpx), curpx->id);
return 1; return 1;
} }
curpx->tcp_rep.inspect_delay = val; curpx->tcp_rep.inspect_delay = val;
@ -1103,7 +1103,7 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
if (strcmp(args[1], "content") == 0) { if (strcmp(args[1], "content") == 0) {
arg++; arg++;
if (tcp_parse_response_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0) if (tcp_parse_response_rule(args, arg, section_type, curpx, defpx, rule, err) < 0)
goto error; goto error;
if (rule->cond && (rule->cond->requires & ACL_USE_L6REQ_VOLATILE)) { if (rule->cond && (rule->cond->requires & ACL_USE_L6REQ_VOLATILE)) {
@ -1113,18 +1113,18 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
acl = cond_find_require(rule->cond, ACL_USE_L6REQ_VOLATILE); acl = cond_find_require(rule->cond, ACL_USE_L6REQ_VOLATILE);
name = acl ? acl->name : "(unknown)"; name = acl ? acl->name : "(unknown)";
retlen = snprintf(err, errlen, memprintf(err,
"acl '%s' involves some request-only criteria which will be ignored.", "acl '%s' involves some request-only criteria which will be ignored in '%s %s'",
name); name, args[0], args[1]);
warn++; warn++;
} }
LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list); LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list);
} }
else { else {
retlen = snprintf(err, errlen, memprintf(err,
"'%s' expects 'inspect-delay' or 'content' in %s '%s' (was '%s')", "'%s' expects 'inspect-delay' or 'content' in %s '%s' (got '%s')",
args[0], proxy_type_str(curpx), curpx->id, args[1]); args[0], proxy_type_str(curpx), curpx->id, args[1]);
goto error; goto error;
} }
@ -1139,41 +1139,42 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
* keyword. * keyword.
*/ */
static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx, static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
const char *ptr = NULL; const char *ptr = NULL;
unsigned int val; unsigned int val;
int retlen;
int warn = 0; int warn = 0;
int arg; int arg;
struct tcp_rule *rule; struct tcp_rule *rule;
if (!*args[1]) { if (!*args[1]) {
snprintf(err, errlen, "missing argument for '%s' in %s '%s'", if (curpx == defpx)
args[0], proxy_type_str(curpx), curpx->id); memprintf(err, "missing argument for '%s' in defaults section", args[0]);
else
memprintf(err, "missing argument for '%s' in %s '%s'",
args[0], proxy_type_str(curpx), curpx->id);
return -1; return -1;
} }
if (!strcmp(args[1], "inspect-delay")) { if (!strcmp(args[1], "inspect-delay")) {
if (curpx == defpx) { if (curpx == defpx) {
snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections", memprintf(err, "%s %s is not allowed in 'defaults' sections",
args[0], args[1]); args[0], args[1]);
return -1; return -1;
} }
if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) { if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
retlen = snprintf(err, errlen, memprintf(err,
"'%s %s' expects a positive delay in milliseconds, in %s '%s'", "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
args[0], args[1], proxy_type_str(curpx), curpx->id); args[0], args[1], proxy_type_str(curpx), curpx->id);
if (ptr && retlen < errlen) if (ptr)
retlen += snprintf(err+retlen, errlen - retlen, memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
" (unexpected character '%c')", *ptr);
return -1; return -1;
} }
if (curpx->tcp_req.inspect_delay) { if (curpx->tcp_req.inspect_delay) {
snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'", memprintf(err, "ignoring %s %s (was already defined) in %s '%s'",
args[0], args[1], proxy_type_str(curpx), curpx->id); args[0], args[1], proxy_type_str(curpx), curpx->id);
return 1; return 1;
} }
curpx->tcp_req.inspect_delay = val; curpx->tcp_req.inspect_delay = val;
@ -1186,7 +1187,7 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
if (strcmp(args[1], "content") == 0) { if (strcmp(args[1], "content") == 0) {
arg++; arg++;
if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0) if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err) < 0)
goto error; goto error;
if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) { if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) {
@ -1196,9 +1197,9 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY); acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY);
name = acl ? acl->name : "(unknown)"; name = acl ? acl->name : "(unknown)";
retlen = snprintf(err, errlen, memprintf(err,
"acl '%s' involves some response-only criteria which will be ignored.", "acl '%s' involves some response-only criteria which will be ignored in '%s %s'",
name); name, args[0], args[1]);
warn++; warn++;
} }
LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list); LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
@ -1207,12 +1208,12 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
arg++; arg++;
if (!(curpx->cap & PR_CAP_FE)) { if (!(curpx->cap & PR_CAP_FE)) {
snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend", memprintf(err, "%s %s is not allowed because %s %s is not a frontend",
args[0], args[1], proxy_type_str(curpx), curpx->id); args[0], args[1], proxy_type_str(curpx), curpx->id);
goto error; goto error;
} }
if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0) if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err) < 0)
goto error; goto error;
if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) { if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
@ -1223,24 +1224,29 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
name = acl ? acl->name : "(unknown)"; name = acl ? acl->name : "(unknown)";
if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) { if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
retlen = snprintf(err, errlen, memprintf(err,
"'%s %s' may not reference acl '%s' which makes use of " "'%s %s' may not reference acl '%s' which makes use of "
"payload in %s '%s'. Please use '%s content' for this.", "payload in %s '%s'. Please use '%s content' for this.",
args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]); args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
goto error; goto error;
} }
if (acl->requires & ACL_USE_RTR_ANY) if (acl->requires & ACL_USE_RTR_ANY)
retlen = snprintf(err, errlen, memprintf(err,
"acl '%s' involves some response-only criteria which will be ignored.", "acl '%s' involves some response-only criteria which will be ignored in '%s %s'",
name); name, args[0], args[1]);
warn++; warn++;
} }
LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list); LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
} }
else { else {
retlen = snprintf(err, errlen, if (curpx == defpx)
"'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')", memprintf(err,
args[0], proxy_type_str(curpx), curpx->id, args[1]); "'%s' expects 'inspect-delay', 'connection', or 'content' in defaults section (got '%s')",
args[0], args[1]);
else
memprintf(err,
"'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (got '%s')",
args[0], args[1], proxy_type_str(curpx), curpx->id);
goto error; goto error;
} }

View File

@ -125,15 +125,15 @@ int get_backend_server(const char *bk_name, const char *sv_name,
/* This function parses a "timeout" statement in a proxy section. It returns /* This function parses a "timeout" statement in a proxy section. It returns
* -1 if there is any error, 1 for a warning, otherwise zero. If it does not * -1 if there is any error, 1 for a warning, otherwise zero. If it does not
* return zero, it may write an error message into the <err> buffer, for at * return zero, it will write an error or warning message into a preallocated
* most <errlen> bytes, trailing zero included. The trailing '\n' must not * buffer returned at <err>. The trailing is not be written. The function must
* be written. The function must be called with <args> pointing to the first * be called with <args> pointing to the first command line word, with <proxy>
* command line word, with <proxy> pointing to the proxy being parsed, and * pointing to the proxy being parsed, and <defpx> to the default proxy or NULL.
* <defpx> to the default proxy or NULL. As a special case for compatibility * As a special case for compatibility with older configs, it also accepts
* with older configs, it also accepts "{cli|srv|con}timeout" in args[0]. * "{cli|srv|con}timeout" in args[0].
*/ */
static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, static int proxy_parse_timeout(char **args, int section, struct proxy *proxy,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
unsigned timeout; unsigned timeout;
int retval, cap; int retval, cap;
@ -184,32 +184,32 @@ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy,
td = &defpx->timeout.queue; td = &defpx->timeout.queue;
cap = PR_CAP_BE; cap = PR_CAP_BE;
} else { } else {
snprintf(err, errlen, memprintf(err,
"timeout '%s': must be 'client', 'server', 'connect', 'check', " "'timeout' supports 'client', 'server', 'connect', 'check', "
"'queue', 'http-keep-alive', 'http-request' or 'tarpit'", "'queue', 'http-keep-alive', 'http-request' or 'tarpit', (got '%s')",
args[0]); args[0]);
return -1; return -1;
} }
if (*args[1] == 0) { if (*args[1] == 0) {
snprintf(err, errlen, "%s timeout expects an integer value (in milliseconds)", name); memprintf(err, "'timeout %s' expects an integer value (in milliseconds)", name);
return -1; return -1;
} }
res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
if (res) { if (res) {
snprintf(err, errlen, "unexpected character '%c' in %s timeout", *res, name); memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name);
return -1; return -1;
} }
if (!(proxy->cap & cap)) { if (!(proxy->cap & cap)) {
snprintf(err, errlen, "%s timeout will be ignored because %s '%s' has no %s capability", memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability",
name, proxy_type_str(proxy), proxy->id, name, proxy_type_str(proxy), proxy->id,
(cap & PR_CAP_BE) ? "backend" : "frontend"); (cap & PR_CAP_BE) ? "backend" : "frontend");
retval = 1; retval = 1;
} }
else if (defpx && *tv != *td) { else if (defpx && *tv != *td) {
snprintf(err, errlen, "overwriting %s timeout which was already specified", name); memprintf(err, "overwriting 'timeout %s' which was already specified", name);
retval = 1; retval = 1;
} }
@ -219,59 +219,51 @@ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy,
/* This function parses a "rate-limit" statement in a proxy section. It returns /* This function parses a "rate-limit" statement in a proxy section. It returns
* -1 if there is any error, 1 for a warning, otherwise zero. If it does not * -1 if there is any error, 1 for a warning, otherwise zero. If it does not
* return zero, it may write an error message into the <err> buffer, for at * return zero, it will write an error or warning message into a preallocated
* most <errlen> bytes, trailing zero included. The trailing '\n' must not * buffer returned at <err>. The function must be called with <args> pointing
* be written. The function must be called with <args> pointing to the first * to the first command line word, with <proxy> pointing to the proxy being
* command line word, with <proxy> pointing to the proxy being parsed, and * parsed, and <defpx> to the default proxy or NULL.
* <defpx> to the default proxy or NULL.
*/ */
static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy, static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
int retval, cap; int retval, cap;
char *res, *name; char *res;
unsigned int *tv = NULL; unsigned int *tv = NULL;
unsigned int *td = NULL; unsigned int *td = NULL;
unsigned int val; unsigned int val;
retval = 0; retval = 0;
/* simply skip "rate-limit" */ if (strcmp(args[1], "sessions") == 0) {
if (strcmp(args[0], "rate-limit") == 0)
args++;
name = args[0];
if (!strcmp(args[0], "sessions")) {
name = "sessions";
tv = &proxy->fe_sps_lim; tv = &proxy->fe_sps_lim;
td = &defpx->fe_sps_lim; td = &defpx->fe_sps_lim;
cap = PR_CAP_FE; cap = PR_CAP_FE;
} else { }
snprintf(err, errlen, else {
"%s '%s': must be 'sessions'", memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]);
"rate-limit", args[0]);
return -1; return -1;
} }
if (*args[1] == 0) { if (*args[2] == 0) {
snprintf(err, errlen, "%s %s expects expects an integer value (in sessions/second)", "rate-limit", name); memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]);
return -1; return -1;
} }
val = strtoul(args[1], &res, 0); val = strtoul(args[2], &res, 0);
if (*res) { if (*res) {
snprintf(err, errlen, "%s %s: unexpected character '%c' in integer value '%s'", "rate-limit", name, *res, args[1]); memprintf(err, "'%s %s' : unexpected character '%c' in integer value '%s'", args[0], args[1], *res, args[2]);
return -1; return -1;
} }
if (!(proxy->cap & cap)) { if (!(proxy->cap & cap)) {
snprintf(err, errlen, "%s %s will be ignored because %s '%s' has no %s capability", memprintf(err, "%s %s will be ignored because %s '%s' has no %s capability",
"rate-limit", name, proxy_type_str(proxy), proxy->id, args[0], args[1], proxy_type_str(proxy), proxy->id,
(cap & PR_CAP_BE) ? "backend" : "frontend"); (cap & PR_CAP_BE) ? "backend" : "frontend");
retval = 1; retval = 1;
} }
else if (defpx && *tv != *td) { else if (defpx && *tv != *td) {
snprintf(err, errlen, "overwriting %s %s which was already specified", "rate-limit", name); memprintf(err, "overwriting %s %s which was already specified", args[0], args[1]);
retval = 1; retval = 1;
} }

View File

@ -3385,10 +3385,9 @@ static struct acl_kw_list acl_kws = {{ },{
int parse_track_counters(char **args, int *arg, int parse_track_counters(char **args, int *arg,
int section_type, struct proxy *curpx, int section_type, struct proxy *curpx,
struct track_ctr_prm *prm, struct track_ctr_prm *prm,
struct proxy *defpx, char *err, int errlen) struct proxy *defpx, char **err)
{ {
int sample_type = 0; int sample_type = 0;
char *kw = args[*arg - 1];
/* parse the arguments of "track-sc[12]" before the condition in the /* parse the arguments of "track-sc[12]" before the condition in the
* following form : * following form :
@ -3401,9 +3400,7 @@ int parse_track_counters(char **args, int *arg,
} }
else if (strcmp(args[*arg], "table") == 0) { else if (strcmp(args[*arg], "table") == 0) {
if (!args[*arg + 1]) { if (!args[*arg + 1]) {
snprintf(err, errlen, memprintf(err, "missing table name");
"missing table for %s in %s '%s'.",
kw, proxy_type_str(curpx), curpx->id);
return -1; return -1;
} }
/* we copy the table name for now, it will be resolved later */ /* we copy the table name for now, it will be resolved later */
@ -3418,9 +3415,9 @@ int parse_track_counters(char **args, int *arg,
} }
if (!sample_type) { if (!sample_type) {
snprintf(err, errlen, memprintf(err,
"%s key not specified in %s '%s' (found %s, only 'src' is supported).", "tracking key not specified (found %s, only 'src' is supported)",
kw, proxy_type_str(curpx), curpx->id, quote_arg(args[*arg])); quote_arg(args[*arg]));
return -1; return -1;
} }