CLEANUP: map/cli: take the "show map" context definition out of the appctx

This makes use of the generic command context allocation so that the
appctx doesn't have to declare a specific one anymore. The context is
created during parsing. Many commands, including pure parsers, use this
context but that's not a problem as it's designed to be used this way.
Due to this, many lines are changed but that's in fact a replacement of
"appctx->ctx.map" with "ctx->". Note that the code also uses st2 which
deserves being addressed in separate commit.
This commit is contained in:
Willy Tarreau 2022-05-03 11:54:47 +02:00
parent 0f154ed1ef
commit 0fcecc63c8
2 changed files with 177 additions and 147 deletions

View File

@ -149,13 +149,6 @@ struct appctx {
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
int st_code; /* the status code returned by an action */
} stats;
struct {
unsigned int display_flags;
struct pat_ref *ref;
struct bref bref; /* back-reference from the pat_ref_elt being dumped */
struct pattern_expr *expr;
struct buffer chunk;
} map;
struct {
struct hlua *hlua;
struct task *task;

317
src/map.c
View File

@ -14,7 +14,7 @@
#include <syslog.h>
#include <haproxy/api.h>
#include <haproxy/applet-t.h>
#include <haproxy/applet.h>
#include <haproxy/arg.h>
#include <haproxy/cli.h>
#include <haproxy/conn_stream.h>
@ -321,9 +321,23 @@ struct pattern_expr *pat_expr_get_next(struct pattern_expr *getnext, struct list
return expr;
}
/* appctx context for the "{show|get|add|del|*} {map|acl}" commands. This is
* used even by commands that only have a parser and no I/O handler because
* it provides a unified way to manipulate some fields and will allow to
* expand some of them more easily later if needed.
*/
struct show_map_ctx {
struct pat_ref *ref;
struct bref bref; /* back-reference from the pat_ref_elt being dumped */
struct pattern_expr *expr;
struct buffer chunk;
unsigned int display_flags;
};
/* expects the current generation ID in appctx->cli.cli.i0 */
static int cli_io_handler_pat_list(struct appctx *appctx)
{
struct show_map_ctx *ctx = appctx->svcctx;
struct conn_stream *cs = appctx->owner;
struct pat_ref_elt *elt;
@ -332,12 +346,12 @@ static int cli_io_handler_pat_list(struct appctx *appctx)
* reference to the last ref_elt being dumped.
*/
if (appctx->st2 == STAT_ST_LIST) {
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users)) {
LIST_DELETE(&appctx->ctx.map.bref.users);
LIST_INIT(&appctx->ctx.map.bref.users);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!LIST_ISEMPTY(&ctx->bref.users)) {
LIST_DELETE(&ctx->bref.users);
LIST_INIT(&ctx->bref.users);
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
return 1;
}
@ -349,19 +363,19 @@ static int cli_io_handler_pat_list(struct appctx *appctx)
/* fall through */
case STAT_ST_LIST:
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users)) {
LIST_DELETE(&appctx->ctx.map.bref.users);
LIST_INIT(&appctx->ctx.map.bref.users);
if (!LIST_ISEMPTY(&ctx->bref.users)) {
LIST_DELETE(&ctx->bref.users);
LIST_INIT(&ctx->bref.users);
} else {
appctx->ctx.map.bref.ref = appctx->ctx.map.ref->head.n;
ctx->bref.ref = ctx->ref->head.n;
}
while (appctx->ctx.map.bref.ref != &appctx->ctx.map.ref->head) {
while (ctx->bref.ref != &ctx->ref->head) {
chunk_reset(&trash);
elt = LIST_ELEM(appctx->ctx.map.bref.ref, struct pat_ref_elt *, list);
elt = LIST_ELEM(ctx->bref.ref, struct pat_ref_elt *, list);
if (elt->gen_id != appctx->ctx.cli.i0)
goto skip;
@ -379,16 +393,16 @@ static int cli_io_handler_pat_list(struct appctx *appctx)
/* let's try again later from this stream. We add ourselves into
* this stream's users so that it can remove us upon termination.
*/
LIST_APPEND(&elt->back_refs, &appctx->ctx.map.bref.users);
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
LIST_APPEND(&elt->back_refs, &ctx->bref.users);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
cs_rx_room_blk(cs);
return 0;
}
skip:
/* get next list entry and check the end of the list */
appctx->ctx.map.bref.ref = elt->list.n;
ctx->bref.ref = elt->list.n;
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
/* fall through */
default:
@ -399,6 +413,7 @@ static int cli_io_handler_pat_list(struct appctx *appctx)
static int cli_io_handler_pats_list(struct appctx *appctx)
{
struct show_map_ctx *ctx = appctx->svcctx;
struct conn_stream *cs = appctx->owner;
switch (appctx->st2) {
@ -419,23 +434,23 @@ static int cli_io_handler_pats_list(struct appctx *appctx)
* available field of this pointer is <list>. It is used with the function
* pat_list_get_next() for returning the first available entry
*/
appctx->ctx.map.ref = LIST_ELEM(&pattern_reference, struct pat_ref *, list);
appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
appctx->ctx.map.display_flags);
ctx->ref = LIST_ELEM(&pattern_reference, struct pat_ref *, list);
ctx->ref = pat_list_get_next(ctx->ref, &pattern_reference,
ctx->display_flags);
appctx->st2 = STAT_ST_LIST;
/* fall through */
case STAT_ST_LIST:
while (appctx->ctx.map.ref) {
while (ctx->ref) {
chunk_reset(&trash);
/* Build messages. If the reference is used by another category than
* the listed categories, display the information in the message.
*/
chunk_appendf(&trash, "%d (%s) %s. curr_ver=%u next_ver=%u entry_cnt=%llu\n", appctx->ctx.map.ref->unique_id,
appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "",
appctx->ctx.map.ref->display, appctx->ctx.map.ref->curr_gen, appctx->ctx.map.ref->next_gen,
appctx->ctx.map.ref->entry_cnt);
chunk_appendf(&trash, "%d (%s) %s. curr_ver=%u next_ver=%u entry_cnt=%llu\n", ctx->ref->unique_id,
ctx->ref->reference ? ctx->ref->reference : "",
ctx->ref->display, ctx->ref->curr_gen, ctx->ref->next_gen,
ctx->ref->entry_cnt);
if (ci_putchk(cs_ic(cs), &trash) == -1) {
/* let's try again later from this stream. We add ourselves into
@ -446,8 +461,8 @@ static int cli_io_handler_pats_list(struct appctx *appctx)
}
/* get next list entry and check the end of the list */
appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
appctx->ctx.map.display_flags);
ctx->ref = pat_list_get_next(ctx->ref, &pattern_reference,
ctx->display_flags);
}
/* fall through */
@ -461,6 +476,7 @@ static int cli_io_handler_pats_list(struct appctx *appctx)
static int cli_io_handler_map_lookup(struct appctx *appctx)
{
struct show_map_ctx *ctx = appctx->svcctx;
struct conn_stream *cs = appctx->owner;
struct sample sample;
struct pattern *pat;
@ -469,48 +485,48 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
switch (appctx->st2) {
case STAT_ST_INIT:
/* Init to the first entry. The list cannot be change */
appctx->ctx.map.expr = LIST_ELEM(&appctx->ctx.map.ref->pat, struct pattern_expr *, list);
appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr, &appctx->ctx.map.ref->pat);
ctx->expr = LIST_ELEM(&ctx->ref->pat, struct pattern_expr *, list);
ctx->expr = pat_expr_get_next(ctx->expr, &ctx->ref->pat);
appctx->st2 = STAT_ST_LIST;
/* fall through */
case STAT_ST_LIST:
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
/* for each lookup type */
while (appctx->ctx.map.expr) {
while (ctx->expr) {
/* initialise chunk to build new message */
chunk_reset(&trash);
/* execute pattern matching */
sample.data.type = SMP_T_STR;
sample.flags = SMP_F_CONST;
sample.data.u.str.data = appctx->ctx.map.chunk.data;
sample.data.u.str.area = appctx->ctx.map.chunk.area;
sample.data.u.str.data = ctx->chunk.data;
sample.data.u.str.area = ctx->chunk.area;
if (appctx->ctx.map.expr->pat_head->match &&
sample_convert(&sample, appctx->ctx.map.expr->pat_head->expect_type))
pat = appctx->ctx.map.expr->pat_head->match(&sample, appctx->ctx.map.expr, 1);
if (ctx->expr->pat_head->match &&
sample_convert(&sample, ctx->expr->pat_head->expect_type))
pat = ctx->expr->pat_head->match(&sample, ctx->expr, 1);
else
pat = NULL;
/* build return message: set type of match */
for (match_method=0; match_method<PAT_MATCH_NUM; match_method++)
if (appctx->ctx.map.expr->pat_head->match == pat_match_fcts[match_method])
if (ctx->expr->pat_head->match == pat_match_fcts[match_method])
break;
if (match_method >= PAT_MATCH_NUM)
chunk_appendf(&trash, "type=unknown(%p)", appctx->ctx.map.expr->pat_head->match);
chunk_appendf(&trash, "type=unknown(%p)", ctx->expr->pat_head->match);
else
chunk_appendf(&trash, "type=%s", pat_match_names[match_method]);
/* case sensitive */
if (appctx->ctx.map.expr->mflags & PAT_MF_IGNORE_CASE)
if (ctx->expr->mflags & PAT_MF_IGNORE_CASE)
chunk_appendf(&trash, ", case=insensitive");
else
chunk_appendf(&trash, ", case=sensitive");
/* Display no match, and set default value */
if (!pat) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
chunk_appendf(&trash, ", found=no");
else
chunk_appendf(&trash, ", match=no");
@ -519,7 +535,7 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
/* Display match and match info */
else {
/* display match */
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
chunk_appendf(&trash, ", found=yes");
else
chunk_appendf(&trash, ", match=yes");
@ -531,7 +547,7 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
chunk_appendf(&trash, ", idx=list");
/* display pattern */
if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
if (ctx->display_flags == PAT_REF_MAP) {
if (pat->ref && pat->ref->pattern)
chunk_appendf(&trash, ", key=\"%s\"", pat->ref->pattern);
else
@ -545,7 +561,7 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
}
/* display return value */
if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
if (ctx->display_flags == PAT_REF_MAP) {
if (pat->data && pat->ref && pat->ref->sample)
chunk_appendf(&trash, ", value=\"%s\", type=\"%s\"", pat->ref->sample,
smp_to_type[pat->data->type]);
@ -561,16 +577,16 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
/* let's try again later from this stream. We add ourselves into
* this stream's users so that it can remove us upon termination.
*/
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
cs_rx_room_blk(cs);
return 0;
}
/* get next entry */
appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr,
&appctx->ctx.map.ref->pat);
ctx->expr = pat_expr_get_next(ctx->expr,
&ctx->ref->pat);
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
/* fall through */
default:
@ -581,31 +597,35 @@ static int cli_io_handler_map_lookup(struct appctx *appctx)
static void cli_release_mlook(struct appctx *appctx)
{
ha_free(&appctx->ctx.map.chunk.area);
struct show_map_ctx *ctx = appctx->svcctx;
ha_free(&ctx->chunk.area);
}
static int cli_parse_get_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
/* Set flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* No parameter. */
if (!*args[2] || !*args[3]) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Missing map identifier and/or key.\n");
else
return cli_err(appctx, "Missing ACL identifier and/or key.\n");
}
/* lookup into the maps */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@ -615,10 +635,10 @@ static int cli_parse_get_map(char **args, char *payload, struct appctx *appctx,
* it may be used over multiple iterations. It's released
* at the end and upon abort anyway.
*/
appctx->ctx.map.chunk.data = strlen(args[3]);
appctx->ctx.map.chunk.size = appctx->ctx.map.chunk.data + 1;
appctx->ctx.map.chunk.area = strdup(args[3]);
if (!appctx->ctx.map.chunk.area)
ctx->chunk.data = strlen(args[3]);
ctx->chunk.size = ctx->chunk.data + 1;
ctx->chunk.area = strdup(args[3]);
if (!ctx->chunk.area)
return cli_err(appctx, "Out of memory error.\n");
return 0;
@ -628,6 +648,8 @@ static int cli_parse_get_map(char **args, char *payload, struct appctx *appctx,
static int cli_parse_prepare_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 ||
strcmp(args[1], "acl") == 0) {
uint next_gen;
@ -635,20 +657,20 @@ static int cli_parse_prepare_map(char **args, char *payload, struct appctx *appc
/* Set ACL or MAP flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* lookup into the refs and check the map flag */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref ||
!(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref ||
!(ctx->ref->flags & ctx->display_flags)) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
}
next_gen = pat_ref_newgen(appctx->ctx.map.ref);
next_gen = pat_ref_newgen(ctx->ref);
return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "New version created: %u\n", next_gen));
}
@ -657,25 +679,29 @@ static int cli_parse_prepare_map(char **args, char *payload, struct appctx *appc
static void cli_release_show_map(struct appctx *appctx)
{
struct show_map_ctx *ctx = appctx->svcctx;
if (appctx->st2 == STAT_ST_LIST) {
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users))
LIST_DELETE(&appctx->ctx.map.bref.users);
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!LIST_ISEMPTY(&ctx->bref.users))
LIST_DELETE(&ctx->bref.users);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
}
static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 ||
strcmp(args[1], "acl") == 0) {
const char *gen = NULL;
/* Set ACL or MAP flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* no parameter: display all map available */
if (!*args[2]) {
@ -693,10 +719,10 @@ static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx,
}
/* lookup into the refs and check the map flag */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref ||
!(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref ||
!(ctx->ref->flags & ctx->display_flags)) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@ -706,9 +732,9 @@ static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx,
if (gen)
appctx->ctx.cli.i0 = str2uic(gen);
else
appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
appctx->ctx.cli.i0 = ctx->ref->curr_gen;
LIST_INIT(&appctx->ctx.map.bref.users);
LIST_INIT(&ctx->bref.users);
appctx->io_handler = cli_io_handler_pat_list;
appctx->io_release = cli_release_show_map;
return 0;
@ -719,19 +745,21 @@ static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx,
static int cli_parse_set_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0) {
char *err;
/* Set flags. */
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
/* Expect three parameters: map name, key and new value. */
if (!*args[2] || !*args[3] || !*args[4])
return cli_err(appctx, "'set map' expects three parameters: map identifier, key and value.\n");
/* Lookup the reference in the maps. */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
/* If the entry identifier start with a '#', it is considered as
@ -754,30 +782,30 @@ static int cli_parse_set_map(char **args, char *payload, struct appctx *appctx,
/* Try to modify the entry. */
err = NULL;
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!pat_ref_set_by_id(appctx->ctx.map.ref, ref, args[4], &err)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!pat_ref_set_by_id(ctx->ref, ref, args[4], &err)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (err)
return cli_dynerr(appctx, memprintf(&err, "%s.\n", err));
else
return cli_err(appctx, "Failed to update an entry.\n");
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
else {
/* Else, use the entry identifier as pattern
* string, and update the value.
*/
err = NULL;
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!pat_ref_set(appctx->ctx.map.ref, args[3], args[4], &err)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!pat_ref_set(ctx->ref, args[3], args[4], &err)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (err)
return cli_dynerr(appctx, memprintf(&err, "%s.\n", err));
else
return cli_err(appctx, "Failed to update an entry.\n");
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
/* The set is done, send message. */
@ -789,6 +817,8 @@ static int cli_parse_set_map(char **args, char *payload, struct appctx *appctx,
static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 ||
strcmp(args[1], "acl") == 0) {
const char *gen = NULL;
@ -798,9 +828,9 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
/* Set flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* For both "map" and "acl" we may have an optional generation
* number specified using a "@" character before the pattern
@ -816,7 +846,7 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
* - one parameter if there is a payload
* If it is "acl", we expect only two parameters
*/
if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
if (ctx->display_flags == PAT_REF_MAP) {
if ((!payload && (!*args[2] || !*args[3] || !*args[4])) ||
(payload && !*args[2]))
return cli_err(appctx,
@ -827,9 +857,9 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
return cli_err(appctx, "'add acl' expects two parameters: ACL identifier and pattern.\n");
/* Lookup for the reference. */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@ -837,8 +867,8 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
if (gen) {
genid = str2uic(gen);
if ((int)(genid - appctx->ctx.map.ref->next_gen) > 0) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if ((int)(genid - ctx->ref->next_gen) > 0) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Version number in the future, please use 'prepare map' before.\n");
else
return cli_err(appctx, "Version number in the future, please use 'prepare acl' before.\n");
@ -848,8 +878,8 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
/* The command "add acl" is prohibited if the reference
* use samples.
*/
if ((appctx->ctx.map.display_flags & PAT_REF_ACL) &&
(appctx->ctx.map.ref->flags & PAT_REF_SMP)) {
if ((ctx->display_flags & PAT_REF_ACL) &&
(ctx->ref->flags & PAT_REF_SMP)) {
return cli_err(appctx,
"This ACL is shared with a map containing samples. "
"You must use the command 'add map' to add values.\n");
@ -876,7 +906,7 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
l = strcspn(key, " \t");
payload += l;
if (!*payload && appctx->ctx.map.display_flags == PAT_REF_MAP)
if (!*payload && ctx->display_flags == PAT_REF_MAP)
return cli_dynerr(appctx, memprintf(&err, "Missing value for key '%s'.\n", key));
key[l] = 0;
@ -892,12 +922,12 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
value[l] = 0;
}
if (appctx->ctx.map.display_flags != PAT_REF_MAP)
if (ctx->display_flags != PAT_REF_MAP)
value = NULL;
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
ret = !!pat_ref_load(appctx->ctx.map.ref, gen ? genid : appctx->ctx.map.ref->curr_gen, key, value, -1, &err);
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
ret = !!pat_ref_load(ctx->ref, gen ? genid : ctx->ref->curr_gen, key, value, -1, &err);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (!ret) {
if (err)
@ -917,23 +947,25 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
static int cli_parse_del_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* Expect two parameters: map name and key. */
if (!*args[2] || !*args[3]) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "This command expects two parameters: map identifier and key.\n");
else
return cli_err(appctx, "This command expects two parameters: ACL identifier and key.\n");
}
/* Lookup the reference in the maps. */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref ||
!(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags))
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref ||
!(ctx->ref->flags & ctx->display_flags))
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
/* If the entry identifier start with a '#', it is considered as
@ -955,25 +987,25 @@ static int cli_parse_del_map(char **args, char *payload, struct appctx *appctx,
return cli_err(appctx, "Malformed identifier. Please use #<id> or <file>.\n");
/* Try to delete the entry. */
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!pat_ref_delete_by_id(appctx->ctx.map.ref, ref)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!pat_ref_delete_by_id(ctx->ref, ref)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
/* The entry is not found, send message. */
return cli_err(appctx, "Key not found.\n");
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
else {
/* Else, use the entry identifier as pattern
* string and try to delete the entry.
*/
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (!pat_ref_delete(appctx->ctx.map.ref, args[3])) {
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (!pat_ref_delete(ctx->ref, args[3])) {
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
/* The entry is not found, send message. */
return cli_err(appctx, "Key not found.\n");
}
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
}
/* The deletion is done, send message. */
@ -987,11 +1019,12 @@ static int cli_parse_del_map(char **args, char *payload, struct appctx *appctx,
*/
static int cli_io_handler_clear_map(struct appctx *appctx)
{
struct show_map_ctx *ctx = appctx->svcctx;
int finished;
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
finished = pat_ref_purge_range(appctx->ctx.map.ref, appctx->ctx.cli.i0, appctx->ctx.cli.i1, 100);
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
finished = pat_ref_purge_range(ctx->ref, appctx->ctx.cli.i0, appctx->ctx.cli.i1, 100);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (!finished) {
/* let's come back later */
@ -1007,14 +1040,16 @@ static int cli_io_handler_clear_map(struct appctx *appctx)
*/
static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
const char *gen = NULL;
/* Set ACL or MAP flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
/* For both "map" and "acl" we may have an optional generation
* number specified using a "@" character before the pattern
@ -1027,17 +1062,17 @@ static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx
/* no parameter */
if (!*args[2]) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Missing map identifier.\n");
else
return cli_err(appctx, "Missing ACL identifier.\n");
}
/* lookup into the refs and check the map flag */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref ||
!(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[2]);
if (!ctx->ref ||
!(ctx->ref->flags & ctx->display_flags)) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@ -1047,7 +1082,7 @@ static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx
if (gen)
appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = str2uic(gen);
else
appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = ctx->ref->curr_gen;
/* delegate the clearing to the I/O handler which can yield */
return 0;
@ -1061,6 +1096,8 @@ static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx
*/
static int cli_parse_commit_map(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
const char *gen = NULL;
uint genid;
@ -1068,9 +1105,9 @@ static int cli_parse_commit_map(char **args, char *payload, struct appctx *appct
/* Set ACL or MAP flags. */
if (args[1][0] == 'm')
appctx->ctx.map.display_flags = PAT_REF_MAP;
ctx->display_flags = PAT_REF_MAP;
else
appctx->ctx.map.display_flags = PAT_REF_ACL;
ctx->display_flags = PAT_REF_ACL;
if (*args[2] != '@')
return cli_err(appctx, "Missing version number.\n");
@ -1086,29 +1123,29 @@ static int cli_parse_commit_map(char **args, char *payload, struct appctx *appct
/* no parameter */
if (!*args[3]) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Missing map identifier.\n");
else
return cli_err(appctx, "Missing ACL identifier.\n");
}
/* lookup into the refs and check the map flag */
appctx->ctx.map.ref = pat_ref_lookup_ref(args[3]);
if (!appctx->ctx.map.ref ||
!(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
ctx->ref = pat_ref_lookup_ref(args[3]);
if (!ctx->ref ||
!(ctx->ref->flags & ctx->display_flags)) {
if (ctx->display_flags == PAT_REF_MAP)
return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
else
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
}
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
if (genid - (appctx->ctx.map.ref->curr_gen + 1) <
appctx->ctx.map.ref->next_gen - appctx->ctx.map.ref->curr_gen)
ret = pat_ref_commit(appctx->ctx.map.ref, genid);
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
if (genid - (ctx->ref->curr_gen + 1) <
ctx->ref->next_gen - ctx->ref->curr_gen)
ret = pat_ref_commit(ctx->ref, genid);
else
ret = 1;
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (ret != 0)
return cli_err(appctx, "Version number out of range.\n");