From: Willy Tarreau Date: Tue, 8 May 2012 17:47:01 +0000 (+0200) Subject: MEDIUM: cfgparse: use the new error reporting framework for remaining cfg_keywords X-Git-Tag: v1.5-dev9~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a3dd74c9cd24ab77178c9ccc65c577a91648cef;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/common/cfgparse.h b/include/common/cfgparse.h index b43f8998be..118d098de4 100644 --- a/include/common/cfgparse.h +++ b/include/common/cfgparse.h @@ -1,23 +1,23 @@ /* - include/common/cfgparse.h - Configuration parsing functions. - - Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, version 2.1 - exclusively. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ + * include/common/cfgparse.h + * Configuration parsing functions. + * + * Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef _COMMON_CFGPARSE_H #define _COMMON_CFGPARSE_H @@ -43,8 +43,7 @@ struct cfg_keyword { int section_type, /* current section CFG_{GLOBAL|LISTEN} */ struct proxy *curpx, /* current proxy (NULL in GLOBAL) */ struct proxy *defpx, /* default proxy (NULL in GLOBAL) */ - char *err, /* error message buffer (do not add '\n') */ - int errlen); /* error buffer size, '\0' included */ + char **err); /* error or warning message output pointer */ }; /* A keyword list. It is a NULL-terminated array of keywords. It embeds a diff --git a/include/proto/session.h b/include/proto/session.h index fb2b6a6605..049fc931c6 100644 --- a/include/proto/session.h +++ b/include/proto/session.h @@ -46,7 +46,7 @@ void default_srv_error(struct session *s, struct stream_interface *si); int parse_track_counters(char **args, int *arg, int section_type, struct proxy *curpx, 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 * pointer to ensure this is only performed once. The caller is responsible for diff --git a/src/cfgparse.c b/src/cfgparse.c index 134794049c..5222652e1c 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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 err_code = 0; + char *errmsg = NULL; if (!strcmp(args[0], "global")) { /* new section */ /* 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 */ snprintf(trash, sizeof(trash), "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) { - Alert("parsing [%s:%d] : %s\n", file, linenum, trash); + Alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); err_code |= ERR_ALERT | ERR_FATAL; } 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; goto out; } @@ -1052,6 +1053,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } out: + free(errmsg); return err_code; } @@ -5249,14 +5251,14 @@ stats_error_parsing: /* prepare error message just in case */ snprintf(trash, sizeof(trash), "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) { - Alert("parsing [%s:%d] : %s\n", file, linenum, trash); + Alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } 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; goto out; } diff --git a/src/dumpstats.c b/src/dumpstats.c index ae19db7968..e22ca1ff25 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -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 - * -1 if there is any error, otherwise zero. If it returns -1, it may write an - * error message into ther buffer, for at most bytes, trailing - * zero included. The trailing '\n' must not be written. The function must be - * called with pointing to the first word after "stats". + * -1 if there is any error, otherwise zero. If it returns -1, it will write an + * error message into the buffer which will be preallocated. The trailing + * '\n' must not be written. The function must be called with pointing to + * the first word after "stats". */ 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[0], "socket")) { + if (!strcmp(args[1], "socket")) { struct sockaddr_un *su; int cur_arg; - if (*args[1] == 0) { - snprintf(err, errlen, "'stats socket' in global section expects a path to a UNIX socket"); + if (*args[2] == 0) { + memprintf(err, "'%s %s' in global section expects a path to a UNIX socket", args[0], args[1]); return -1; } 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; } - su = str2sun(args[1]); + su = str2sun(args[2]); 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; } memcpy(&global.stats_sock.addr, su, sizeof(struct sockaddr_un)); // guaranteed to fit if (!global.stats_fe) { 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; } } @@ -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_fe->listen = &global.stats_sock; - cur_arg = 2; + cur_arg = 3; while (*args[cur_arg]) { if (!strcmp(args[cur_arg], "uid")) { 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; user = getpwnam(args[cur_arg + 1]); if (!user) { - snprintf(err, errlen, "unknown user '%s' in 'global' section ('stats user')", - args[cur_arg + 1]); + memprintf(err, "'%s %s' : unknown user '%s'", args[0], args[1], args[cur_arg + 1]); return -1; } 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; group = getgrnam(args[cur_arg + 1]); if (!group) { - snprintf(err, errlen, "unknown group '%s' in 'global' section ('stats group')", - args[cur_arg + 1]); + memprintf(err, "'%s %s' : unknown group '%s'", args[0], args[1], args[cur_arg + 1]); return -1; } 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")) global.stats_sock.perm.ux.level = ACCESS_LVL_ADMIN; 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; } cur_arg += 2; } 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; } } @@ -280,45 +279,45 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx uxst_add_listener(&global.stats_sock); global.maxsock++; } - else if (!strcmp(args[0], "timeout")) { + else if (!strcmp(args[1], "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) { - 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; } 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; } if (!global.stats_fe) { 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; } } global.stats_fe->timeout.client = MS_TO_TICKS(timeout); } - else if (!strcmp(args[0], "maxconn")) { - int maxconn = atol(args[1]); + else if (!strcmp(args[1], "maxconn")) { + int maxconn = atol(args[2]); 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; } if (!global.stats_fe) { 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; } } global.stats_fe->maxconn = maxconn; } 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 0; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 80a7c66b3f..2acdf986bf 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -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 */ static int tcp_parse_response_rule(char **args, int arg, int section_type, 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)) { - snprintf(err, errlen, "%s %s is only allowed in 'backend' sections", - args[0], args[1]); + memprintf(err, "%s %s is only allowed in 'backend' sections", + args[0], args[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; } else { - snprintf(err, errlen, - "'%s %s' expects 'accept' or 'reject' in %s '%s' (was '%s')", - args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); + memprintf(err, + "'%s %s' expects 'accept' or 'reject' in %s '%s' (got '%s')", + args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); return -1; } 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, &errmsg)) == NULL) { - snprintf(err, errlen, - "error detected in %s '%s' while parsing '%s' condition : %s", - proxy_type_str(curpx), curpx->id, args[arg], errmsg); - free(errmsg); + if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, err)) == NULL) { + memprintf(err, + "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s", + args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err); return -1; } } else if (*args[arg]) { - snprintf(err, errlen, - "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')", + memprintf(err, + "'%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]); 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 */ static int tcp_parse_request_rule(char **args, int arg, int section_type, struct proxy *curpx, struct proxy *defpx, - struct tcp_rule *rule, char *err, int errlen) + struct tcp_rule *rule, char **err) { if (curpx == defpx) { - snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections", - args[0], args[1]); + memprintf(err, "%s %s is not allowed in 'defaults' sections", + args[0], args[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) { int ret; + int kw = arg; arg++; ret = parse_track_counters(args, &arg, section_type, curpx, - &rule->act_prm.trk_ctr, defpx, err, errlen); - - if (ret < 0) /* nb: warnings are not handled yet */ - return -1; + &rule->act_prm.trk_ctr, defpx, err); + 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; } else if (strcmp(args[arg], "track-sc2") == 0) { int ret; + int kw = arg; arg++; ret = parse_track_counters(args, &arg, section_type, curpx, - &rule->act_prm.trk_ctr, defpx, err, errlen); - - if (ret < 0) /* nb: warnings are not handled yet */ - return -1; + &rule->act_prm.trk_ctr, defpx, err); + 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; } else { - snprintf(err, errlen, - "'%s %s' expects 'accept', 'reject', 'track-sc1' " - "or 'track-sc2' in %s '%s' (was '%s')", - args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); + memprintf(err, + "'%s %s' expects 'accept', 'reject', 'track-sc1' " + "or 'track-sc2' in %s '%s' (got '%s')", + args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]); return -1; } 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, &errmsg)) == NULL) { - snprintf(err, errlen, - "error detected in %s '%s' while parsing '%s' condition : %s", - proxy_type_str(curpx), curpx->id, args[arg], errmsg); - free(errmsg); + if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, err)) == NULL) { + memprintf(err, + "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s", + args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err); return -1; } } else if (*args[arg]) { - snprintf(err, errlen, - "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')", + memprintf(err, + "'%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]); return -1; } @@ -1056,41 +1058,39 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, * keyword. */ 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; unsigned int val; - int retlen; int warn = 0; int arg; struct tcp_rule *rule; if (!*args[1]) { - snprintf(err, errlen, "missing argument for '%s' in %s '%s'", - args[0], proxy_type_str(curpx), curpx->id); + memprintf(err, "missing argument for '%s' in %s '%s'", + args[0], proxy_type_str(curpx), curpx->id); return -1; } if (strcmp(args[1], "inspect-delay") == 0) { if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) { - snprintf(err, errlen, "%s %s is only allowed in 'backend' sections", - args[0], args[1]); + memprintf(err, "%s %s is only allowed in 'backend' sections", + args[0], args[1]); return -1; } if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) { - retlen = snprintf(err, errlen, - "'%s %s' expects a positive delay in milliseconds, in %s '%s'", - args[0], args[1], proxy_type_str(curpx), curpx->id); - if (ptr && retlen < errlen) - retlen += snprintf(err + retlen, errlen - retlen, - " (unexpected character '%c')", *ptr); + memprintf(err, + "'%s %s' expects a positive delay in milliseconds, in %s '%s'", + args[0], args[1], proxy_type_str(curpx), curpx->id); + if (ptr) + memprintf(err, "%s (unexpected character '%c')", *err, *ptr); return -1; } if (curpx->tcp_rep.inspect_delay) { - snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'", - args[0], args[1], proxy_type_str(curpx), curpx->id); + memprintf(err, "ignoring %s %s (was already defined) in %s '%s'", + args[0], args[1], proxy_type_str(curpx), curpx->id); return 1; } 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) { 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; 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); name = acl ? acl->name : "(unknown)"; - retlen = snprintf(err, errlen, - "acl '%s' involves some request-only criteria which will be ignored.", - name); + memprintf(err, + "acl '%s' involves some request-only criteria which will be ignored in '%s %s'", + name, args[0], args[1]); warn++; } LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list); } else { - retlen = snprintf(err, errlen, - "'%s' expects 'inspect-delay' or 'content' in %s '%s' (was '%s')", - args[0], proxy_type_str(curpx), curpx->id, args[1]); + memprintf(err, + "'%s' expects 'inspect-delay' or 'content' in %s '%s' (got '%s')", + args[0], proxy_type_str(curpx), curpx->id, args[1]); goto error; } @@ -1139,41 +1139,42 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx, * keyword. */ 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; unsigned int val; - int retlen; int warn = 0; int arg; struct tcp_rule *rule; if (!*args[1]) { - snprintf(err, errlen, "missing argument for '%s' in %s '%s'", - args[0], proxy_type_str(curpx), curpx->id); + if (curpx == defpx) + 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; } if (!strcmp(args[1], "inspect-delay")) { if (curpx == defpx) { - snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections", - args[0], args[1]); + memprintf(err, "%s %s is not allowed in 'defaults' sections", + args[0], args[1]); return -1; } if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) { - retlen = snprintf(err, errlen, - "'%s %s' expects a positive delay in milliseconds, in %s '%s'", - args[0], args[1], proxy_type_str(curpx), curpx->id); - if (ptr && retlen < errlen) - retlen += snprintf(err+retlen, errlen - retlen, - " (unexpected character '%c')", *ptr); + memprintf(err, + "'%s %s' expects a positive delay in milliseconds, in %s '%s'", + args[0], args[1], proxy_type_str(curpx), curpx->id); + if (ptr) + memprintf(err, "%s (unexpected character '%c')", *err, *ptr); return -1; } if (curpx->tcp_req.inspect_delay) { - snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'", - args[0], args[1], proxy_type_str(curpx), curpx->id); + memprintf(err, "ignoring %s %s (was already defined) in %s '%s'", + args[0], args[1], proxy_type_str(curpx), curpx->id); return 1; } 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) { 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; 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); name = acl ? acl->name : "(unknown)"; - retlen = snprintf(err, errlen, - "acl '%s' involves some response-only criteria which will be ignored.", - name); + memprintf(err, + "acl '%s' involves some response-only criteria which will be ignored in '%s %s'", + name, args[0], args[1]); warn++; } 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++; if (!(curpx->cap & PR_CAP_FE)) { - snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend", - args[0], args[1], proxy_type_str(curpx), curpx->id); + memprintf(err, "%s %s is not allowed because %s %s is not a frontend", + args[0], args[1], proxy_type_str(curpx), curpx->id); 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; 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)"; if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) { - retlen = snprintf(err, errlen, - "'%s %s' may not reference acl '%s' which makes use of " - "payload in %s '%s'. Please use '%s content' for this.", - args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]); + memprintf(err, + "'%s %s' may not reference acl '%s' which makes use of " + "payload in %s '%s'. Please use '%s content' for this.", + args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]); goto error; } if (acl->requires & ACL_USE_RTR_ANY) - retlen = snprintf(err, errlen, - "acl '%s' involves some response-only criteria which will be ignored.", - name); + memprintf(err, + "acl '%s' involves some response-only criteria which will be ignored in '%s %s'", + name, args[0], args[1]); warn++; } LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list); } else { - retlen = snprintf(err, errlen, - "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')", - args[0], proxy_type_str(curpx), curpx->id, args[1]); + if (curpx == defpx) + memprintf(err, + "'%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; } diff --git a/src/proxy.c b/src/proxy.c index bb9fe5733d..9ae9889814 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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 * -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 buffer, for at - * most bytes, trailing zero included. The trailing '\n' must not - * be written. The function must be called with pointing to the first - * command line word, with pointing to the proxy being parsed, and - * to the default proxy or NULL. As a special case for compatibility - * with older configs, it also accepts "{cli|srv|con}timeout" in args[0]. + * return zero, it will write an error or warning message into a preallocated + * buffer returned at . The trailing is not be written. The function must + * be called with pointing to the first command line word, with + * pointing to the proxy being parsed, and to the default proxy or NULL. + * As a special case for compatibility with older configs, it also accepts + * "{cli|srv|con}timeout" in args[0]. */ 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; int retval, cap; @@ -184,32 +184,32 @@ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, td = &defpx->timeout.queue; cap = PR_CAP_BE; } else { - snprintf(err, errlen, - "timeout '%s': must be 'client', 'server', 'connect', 'check', " - "'queue', 'http-keep-alive', 'http-request' or 'tarpit'", - args[0]); + memprintf(err, + "'timeout' supports 'client', 'server', 'connect', 'check', " + "'queue', 'http-keep-alive', 'http-request' or 'tarpit', (got '%s')", + args[0]); return -1; } 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; } res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); 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; } if (!(proxy->cap & cap)) { - snprintf(err, errlen, "%s timeout will be ignored because %s '%s' has no %s capability", - name, proxy_type_str(proxy), proxy->id, - (cap & PR_CAP_BE) ? "backend" : "frontend"); + memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability", + name, proxy_type_str(proxy), proxy->id, + (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } 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; } @@ -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 * -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 buffer, for at - * most bytes, trailing zero included. The trailing '\n' must not - * be written. The function must be called with pointing to the first - * command line word, with pointing to the proxy being parsed, and - * to the default proxy or NULL. + * return zero, it will write an error or warning message into a preallocated + * buffer returned at . The function must be called with pointing + * to the first command line word, with pointing to the proxy being + * parsed, and to the default proxy or NULL. */ 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; - char *res, *name; + char *res; unsigned int *tv = NULL; unsigned int *td = NULL; unsigned int val; retval = 0; - /* simply skip "rate-limit" */ - if (strcmp(args[0], "rate-limit") == 0) - args++; - - name = args[0]; - if (!strcmp(args[0], "sessions")) { - name = "sessions"; + if (strcmp(args[1], "sessions") == 0) { tv = &proxy->fe_sps_lim; td = &defpx->fe_sps_lim; cap = PR_CAP_FE; - } else { - snprintf(err, errlen, - "%s '%s': must be 'sessions'", - "rate-limit", args[0]); + } + else { + memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]); return -1; } - if (*args[1] == 0) { - snprintf(err, errlen, "%s %s expects expects an integer value (in sessions/second)", "rate-limit", name); + if (*args[2] == 0) { + memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]); return -1; } - val = strtoul(args[1], &res, 0); + val = strtoul(args[2], &res, 0); 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; } if (!(proxy->cap & cap)) { - snprintf(err, errlen, "%s %s will be ignored because %s '%s' has no %s capability", - "rate-limit", name, proxy_type_str(proxy), proxy->id, + memprintf(err, "%s %s will be ignored because %s '%s' has no %s capability", + args[0], args[1], proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } 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; } diff --git a/src/session.c b/src/session.c index cd02da24d4..feb0283205 100644 --- a/src/session.c +++ b/src/session.c @@ -3385,10 +3385,9 @@ static struct acl_kw_list acl_kws = {{ },{ int parse_track_counters(char **args, int *arg, int section_type, struct proxy *curpx, struct track_ctr_prm *prm, - struct proxy *defpx, char *err, int errlen) + struct proxy *defpx, char **err) { int sample_type = 0; - char *kw = args[*arg - 1]; /* parse the arguments of "track-sc[12]" before the condition in the * following form : @@ -3401,9 +3400,7 @@ int parse_track_counters(char **args, int *arg, } else if (strcmp(args[*arg], "table") == 0) { if (!args[*arg + 1]) { - snprintf(err, errlen, - "missing table for %s in %s '%s'.", - kw, proxy_type_str(curpx), curpx->id); + memprintf(err, "missing table name"); return -1; } /* 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) { - snprintf(err, errlen, - "%s key not specified in %s '%s' (found %s, only 'src' is supported).", - kw, proxy_type_str(curpx), curpx->id, quote_arg(args[*arg])); + memprintf(err, + "tracking key not specified (found %s, only 'src' is supported)", + quote_arg(args[*arg])); return -1; }