STAT_CLI_O_CLR, /* clear tables */
STAT_CLI_O_SET, /* set entries in tables */
STAT_CLI_O_STAT, /* dump stats */
- STAT_CLI_O_PATS, /* list all pattern reference available */
- STAT_CLI_O_PAT, /* list all entries of a pattern */
- STAT_CLI_O_MLOOK, /* lookup a map entry */
STAT_CLI_O_POOLS, /* dump memory pools */
STAT_CLI_O_RESOLVERS,/* dump a resolver's section nameservers counters */
STAT_CLI_O_SERVERS_STATE, /* dump server state and changing information */
static int stats_dump_errors_to_buffer(struct stream_interface *si);
static int stats_table_request(struct stream_interface *si, int show);
static int stats_dump_resolvers_to_buffer(struct stream_interface *si);
-static int stats_pats_list(struct stream_interface *si);
-static int stats_pat_list(struct stream_interface *si);
-static int stats_map_lookup(struct stream_interface *si);
static int dump_servers_state(struct stream_interface *si, struct chunk *buf);
" disable : put a server or frontend in maintenance mode\n"
" enable : re-enable a server or frontend which is in maintenance mode\n"
" shutdown : kill a session or a frontend (eg:to release listening ports)\n"
- " show acl [id] : report available acls or dump an acl's contents\n"
- " get acl : reports the patterns matching a sample for an ACL\n"
- " add acl : add acl entry\n"
- " del acl : delete acl entry\n"
- " clear acl <id> : clear the content of this acl\n"
- " show map [id] : report available maps or dump a map's contents\n"
- " get map : reports the keys and values matching a sample for a map\n"
- " set map : modify map entry\n"
- " add map : add map entry\n"
- " del map : delete map entry\n"
- " clear map <id> : clear the content of this map\n"
"";
static const char stats_permission_denied_msg[] =
return sv;
}
-
-/* This function is used with map and acl management. It permits to browse
- * each reference. The variable <getnext> must contain the current node,
- * <end> point to the root node and the <flags> permit to filter required
- * nodes.
- */
-static inline
-struct pat_ref *pat_list_get_next(struct pat_ref *getnext, struct list *end,
- unsigned int flags)
-{
- struct pat_ref *ref = getnext;
-
- while (1) {
-
- /* Get next list entry. */
- ref = LIST_NEXT(&ref->list, struct pat_ref *, list);
-
- /* If the entry is the last of the list, return NULL. */
- if (&ref->list == end)
- return NULL;
-
- /* If the entry match the flag, return it. */
- if (ref->flags & flags)
- return ref;
- }
-}
-
-static inline
-struct pat_ref *pat_ref_lookup_ref(const char *reference)
-{
- int id;
- char *error;
-
- /* If the reference starts by a '#', this is numeric id. */
- if (reference[0] == '#') {
- /* Try to convert the numeric id. If the conversion fails, the lookup fails. */
- id = strtol(reference + 1, &error, 10);
- if (*error != '\0')
- return NULL;
-
- /* Perform the unique id lookup. */
- return pat_ref_lookupid(id);
- }
-
- /* Perform the string lookup. */
- return pat_ref_lookup(reference);
-}
-
-/* This function is used with map and acl management. It permits to browse
- * each reference.
- */
-static inline
-struct pattern_expr *pat_expr_get_next(struct pattern_expr *getnext, struct list *end)
-{
- struct pattern_expr *expr;
- expr = LIST_NEXT(&getnext->list, struct pattern_expr *, list);
- if (&expr->list == end)
- return NULL;
- return expr;
-}
-
/* Processes the stats interpreter on the statistics socket. This function is
* called from an applet running in a stream interface. The function returns 1
* if the request was understood, otherwise zero. It sets appctx->st0 to a value
else if (strcmp(args[1], "table") == 0) {
stats_sock_table_request(si, args, STAT_CLI_O_TAB);
}
- else if (strcmp(args[1], "map") == 0 ||
- strcmp(args[1], "acl") == 0) {
-
- /* Set ACL or MAP flags. */
- if (args[1][0] == 'm')
- appctx->ctx.map.display_flags = PAT_REF_MAP;
- else
- appctx->ctx.map.display_flags = PAT_REF_ACL;
-
- /* no parameter: display all map available */
- if (!*args[2]) {
- appctx->st2 = STAT_ST_INIT;
- appctx->st0 = STAT_CLI_O_PATS;
- return 1;
- }
-
- /* 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)
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- appctx->st2 = STAT_ST_INIT;
- appctx->st0 = STAT_CLI_O_PAT;
- }
else { /* neither "stat" nor "info" nor "sess" nor "errors" nor "table" */
return 0;
}
/* end of processing */
return 1;
}
- else if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
- /* Set ACL or MAP flags. */
- if (args[1][0] == 'm')
- appctx->ctx.map.display_flags = PAT_REF_MAP;
- else
- appctx->ctx.map.display_flags = PAT_REF_ACL;
-
- /* no parameter */
- if (!*args[2]) {
- if (appctx->ctx.map.display_flags == PAT_REF_MAP)
- appctx->ctx.cli.msg = "Missing map identifier.\n";
- else
- appctx->ctx.cli.msg = "Missing ACL identifier.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* 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)
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Clear all. */
- pat_ref_prune(appctx->ctx.map.ref);
-
- /* return response */
- appctx->st0 = STAT_CLI_PROMPT;
- return 1;
- }
else {
/* unknown "clear" argument */
return 0;
return 1;
}
- else 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;
- else
- appctx->ctx.map.display_flags = PAT_REF_ACL;
-
- /* No parameter. */
- if (!*args[2] || !*args[3]) {
- if (appctx->ctx.map.display_flags == PAT_REF_MAP)
- appctx->ctx.cli.msg = "Missing map identifier and/or key.\n";
- else
- appctx->ctx.cli.msg = "Missing ACL identifier and/or key.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* 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)
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* copy input string. The string must be allocated because
- * it may be used over multiple iterations. It's released
- * at the end and upon abort anyway.
- */
- appctx->ctx.map.chunk.len = strlen(args[3]);
- appctx->ctx.map.chunk.size = appctx->ctx.map.chunk.len + 1;
- appctx->ctx.map.chunk.str = strdup(args[3]);
- if (!appctx->ctx.map.chunk.str) {
- appctx->ctx.cli.msg = "Out of memory error.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* prepare response */
- appctx->st2 = STAT_ST_INIT;
- appctx->st0 = STAT_CLI_O_MLOOK;
- }
else { /* not "get weight" */
return 0;
}
}
else if (strcmp(args[1], "table") == 0) {
stats_sock_table_request(si, args, STAT_CLI_O_SET);
- }
- else if (strcmp(args[1], "map") == 0) {
- char *err;
-
- /* Set flags. */
- appctx->ctx.map.display_flags = PAT_REF_MAP;
-
- /* Expect three parameters: map name, key and new value. */
- if (!*args[2] || !*args[3] || !*args[4]) {
- appctx->ctx.cli.msg = "'set map' expects three parameters: map identifier, key and value.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Lookup the reference in the maps. */
- appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
- if (!appctx->ctx.map.ref) {
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* If the entry identifier start with a '#', it is considered as
- * pointer id
- */
- if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
- struct pat_ref_elt *ref;
- long long int conv;
- char *error;
-
- /* Convert argument to integer value. */
- conv = strtoll(&args[3][1], &error, 16);
- if (*error != '\0') {
- appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Convert and check integer to pointer. */
- ref = (struct pat_ref_elt *)(long)conv;
- if ((long long int)(long)ref != conv) {
- appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Try to delete the entry. */
- err = NULL;
- if (!pat_ref_set_by_id(appctx->ctx.map.ref, ref, args[4], &err)) {
- if (err)
- memprintf(&err, "%s.\n", err);
- appctx->ctx.cli.err = err;
- appctx->st0 = STAT_CLI_PRINT_FREE;
- return 1;
- }
- }
- else {
- /* Else, use the entry identifier as pattern
- * string, and update the value.
- */
- err = NULL;
- if (!pat_ref_set(appctx->ctx.map.ref, args[3], args[4], &err)) {
- if (err)
- memprintf(&err, "%s.\n", err);
- appctx->ctx.cli.err = err;
- appctx->st0 = STAT_CLI_PRINT_FREE;
- return 1;
- }
- }
-
- /* The set is done, send message. */
- appctx->st0 = STAT_CLI_PROMPT;
- return 1;
} else { /* unknown "set" parameter */
return 0;
}
return 1;
}
}
- else if (strcmp(args[0], "del") == 0) {
- if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
- if (args[1][0] == 'm')
- appctx->ctx.map.display_flags = PAT_REF_MAP;
- else
- appctx->ctx.map.display_flags = PAT_REF_ACL;
-
- /* Expect two parameters: map name and key. */
- if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
- if (!*args[2] || !*args[3]) {
- appctx->ctx.cli.msg = "This command expects two parameters: map identifier and key.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
-
- else {
- if (!*args[2] || !*args[3]) {
- appctx->ctx.cli.msg = "This command expects two parameters: ACL identifier and key.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
-
- /* 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)) {
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* If the entry identifier start with a '#', it is considered as
- * pointer id
- */
- if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
- struct pat_ref_elt *ref;
- long long int conv;
- char *error;
-
- /* Convert argument to integer value. */
- conv = strtoll(&args[3][1], &error, 16);
- if (*error != '\0') {
- appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Convert and check integer to pointer. */
- ref = (struct pat_ref_elt *)(long)conv;
- if ((long long int)(long)ref != conv) {
- appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Try to delete the entry. */
- if (!pat_ref_delete_by_id(appctx->ctx.map.ref, ref)) {
- /* The entry is not found, send message. */
- appctx->ctx.cli.msg = "Key not found.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
- else {
- /* Else, use the entry identifier as pattern
- * string and try to delete the entry.
- */
- if (!pat_ref_delete(appctx->ctx.map.ref, args[3])) {
- /* The entry is not found, send message. */
- appctx->ctx.cli.msg = "Key not found.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
-
- /* The deletion is done, send message. */
- appctx->st0 = STAT_CLI_PROMPT;
- return 1;
- }
- else { /* unknown "del" parameter */
- appctx->ctx.cli.msg = "'del' only supports 'map' or 'acl'.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
- else if (strcmp(args[0], "add") == 0) {
- if (strcmp(args[1], "map") == 0 ||
- strcmp(args[1], "acl") == 0) {
- int ret;
- char *err;
-
- /* Set flags. */
- if (args[1][0] == 'm')
- appctx->ctx.map.display_flags = PAT_REF_MAP;
- else
- appctx->ctx.map.display_flags = PAT_REF_ACL;
-
- /* If the keywork is "map", we expect three parameters, if it
- * is "acl", we expect only two parameters
- */
- if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
- if (!*args[2] || !*args[3] || !*args[4]) {
- appctx->ctx.cli.msg = "'add map' expects three parameters: map identifier, key and value.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
- else {
- if (!*args[2] || !*args[3]) {
- appctx->ctx.cli.msg = "'add acl' expects two parameters: ACL identifier and pattern.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
-
- /* 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)
- appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
- else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* 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)) {
- appctx->ctx.cli.msg = "This ACL is shared with a map containing samples. "
- "You must use the command 'add map' to add values.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
-
- /* Add value. */
- err = NULL;
- if (appctx->ctx.map.display_flags == PAT_REF_MAP)
- ret = pat_ref_add(appctx->ctx.map.ref, args[3], args[4], &err);
- else
- ret = pat_ref_add(appctx->ctx.map.ref, args[3], NULL, &err);
- if (!ret) {
- if (err)
- memprintf(&err, "%s.\n", err);
- appctx->ctx.cli.err = err;
- appctx->st0 = STAT_CLI_PRINT_FREE;
- return 1;
- }
-
- /* The add is done, send message. */
- appctx->st0 = STAT_CLI_PROMPT;
- return 1;
- }
- else { /* unknown "del" parameter */
- appctx->ctx.cli.msg = "'add' only supports 'map'.\n";
- appctx->st0 = STAT_CLI_PRINT;
- return 1;
- }
- }
else { /* not "show" nor "clear" nor "get" nor "set" nor "enable" nor "disable" */
return 0;
}
if (stats_table_request(si, appctx->st0))
appctx->st0 = STAT_CLI_PROMPT;
break;
- case STAT_CLI_O_PATS:
- if (stats_pats_list(si))
- appctx->st0 = STAT_CLI_PROMPT;
- break;
- case STAT_CLI_O_PAT:
- if (stats_pat_list(si))
- appctx->st0 = STAT_CLI_PROMPT;
- break;
- case STAT_CLI_O_MLOOK:
- if (stats_map_lookup(si))
- appctx->st0 = STAT_CLI_PROMPT;
- break;
case STAT_CLI_O_POOLS:
if (stats_dump_pools_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT;
return 1;
}
-static int stats_pats_list(struct stream_interface *si)
-{
- struct appctx *appctx = __objt_appctx(si->end);
-
- switch (appctx->st2) {
- case STAT_ST_INIT:
- /* Display the column headers. If the message cannot be sent,
- * quit the fucntion with returning 0. The function is called
- * later and restart at the state "STAT_ST_INIT".
- */
- chunk_reset(&trash);
- chunk_appendf(&trash, "# id (file) description\n");
- if (bi_putchk(si_ic(si), &trash) == -1) {
- si_applet_cant_put(si);
- return 0;
- }
-
- /* Now, we start the browsing of the references lists.
- * Note that the following call to LIST_ELEM return bad pointer. The only
- * available field of this pointer is <list>. It is used with the function
- * pat_list_get_next() for retruning 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);
- appctx->st2 = STAT_ST_LIST;
- /* fall through */
-
- case STAT_ST_LIST:
- while (appctx->ctx.map.ref) {
- chunk_reset(&trash);
-
- /* Build messages. If the reference is used by another category than
- * the listed categorie, display the information in the massage.
- */
- chunk_appendf(&trash, "%d (%s) %s\n", appctx->ctx.map.ref->unique_id,
- appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "",
- appctx->ctx.map.ref->display);
-
- if (bi_putchk(si_ic(si), &trash) == -1) {
- /* let's try again later from this stream. We add ourselves into
- * this stream's users so that it can remove us upon termination.
- */
- si_applet_cant_put(si);
- return 0;
- }
-
- /* 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);
- }
-
- appctx->st2 = STAT_ST_FIN;
- /* fall through */
-
- default:
- appctx->st2 = STAT_ST_FIN;
- return 1;
- }
- return 0;
-}
-
-static int stats_map_lookup(struct stream_interface *si)
-{
- struct appctx *appctx = __objt_appctx(si->end);
- struct sample sample;
- struct pattern *pat;
- int match_method;
-
- 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);
- appctx->st2 = STAT_ST_LIST;
- /* fall through */
-
- case STAT_ST_LIST:
- /* for each lookup type */
- while (appctx->ctx.map.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.len = appctx->ctx.map.chunk.len;
- sample.data.u.str.str = appctx->ctx.map.chunk.str;
- 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);
- 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])
- break;
- if (match_method >= PAT_MATCH_NUM)
- chunk_appendf(&trash, "type=unknown(%p)", appctx->ctx.map.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)
- 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)
- chunk_appendf(&trash, ", found=no");
- else
- chunk_appendf(&trash, ", match=no");
- }
-
- /* Display match and match info */
- else {
- /* display match */
- if (appctx->ctx.map.display_flags == PAT_REF_MAP)
- chunk_appendf(&trash, ", found=yes");
- else
- chunk_appendf(&trash, ", match=yes");
-
- /* display index mode */
- if (pat->sflags & PAT_SF_TREE)
- chunk_appendf(&trash, ", idx=tree");
- else
- chunk_appendf(&trash, ", idx=list");
-
- /* display pattern */
- if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
- if (pat->ref && pat->ref->pattern)
- chunk_appendf(&trash, ", key=\"%s\"", pat->ref->pattern);
- else
- chunk_appendf(&trash, ", key=unknown");
- }
- else {
- if (pat->ref && pat->ref->pattern)
- chunk_appendf(&trash, ", pattern=\"%s\"", pat->ref->pattern);
- else
- chunk_appendf(&trash, ", pattern=unknown");
- }
-
- /* display return value */
- if (appctx->ctx.map.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]);
- else
- chunk_appendf(&trash, ", value=none");
- }
- }
-
- chunk_appendf(&trash, "\n");
-
- /* display response */
- if (bi_putchk(si_ic(si), &trash) == -1) {
- /* let's try again later from this stream. We add ourselves into
- * this stream's users so that it can remove us upon termination.
- */
- si_applet_cant_put(si);
- return 0;
- }
-
- /* get next entry */
- appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr,
- &appctx->ctx.map.ref->pat);
- }
-
- appctx->st2 = STAT_ST_FIN;
- /* fall through */
-
- default:
- appctx->st2 = STAT_ST_FIN;
- free(appctx->ctx.map.chunk.str);
- return 1;
- }
-}
-
-static int stats_pat_list(struct stream_interface *si)
-{
- struct appctx *appctx = __objt_appctx(si->end);
-
- switch (appctx->st2) {
-
- case STAT_ST_INIT:
- /* Init to the first entry. The list cannot be change */
- appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.ref->head,
- struct pat_ref_elt *, list);
- if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
- appctx->ctx.map.elt = NULL;
- appctx->st2 = STAT_ST_LIST;
- /* fall through */
-
- case STAT_ST_LIST:
- while (appctx->ctx.map.elt) {
- chunk_reset(&trash);
-
- /* build messages */
- if (appctx->ctx.map.elt->sample)
- chunk_appendf(&trash, "%p %s %s\n",
- appctx->ctx.map.elt, appctx->ctx.map.elt->pattern,
- appctx->ctx.map.elt->sample);
- else
- chunk_appendf(&trash, "%p %s\n",
- appctx->ctx.map.elt, appctx->ctx.map.elt->pattern);
-
- if (bi_putchk(si_ic(si), &trash) == -1) {
- /* let's try again later from this stream. We add ourselves into
- * this stream's users so that it can remove us upon termination.
- */
- si_applet_cant_put(si);
- return 0;
- }
-
- /* get next list entry and check the end of the list */
- appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.elt->list,
- struct pat_ref_elt *, list);
- if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
- break;
- }
-
- appctx->st2 = STAT_ST_FIN;
- /* fall through */
-
- default:
- appctx->st2 = STAT_ST_FIN;
- return 1;
- }
-}
-
/* This function dumps all streams' states onto the stream interface's
* read buffer. It returns 0 if the output buffer is full and it needs
* to be called again, otherwise non-zero. It is designed to be called
free(appctx->ctx.cli.err);
appctx->ctx.cli.err = NULL;
}
- else if (appctx->st0 == STAT_CLI_O_MLOOK) {
- free(appctx->ctx.map.chunk.str);
- appctx->ctx.map.chunk.str = NULL;
- }
}
/* This function is used to either dump tables states (when action is set
#include <common/standard.h>
+#include <types/applet.h>
+#include <types/cli.h>
#include <types/global.h>
#include <types/map.h>
#include <types/pattern.h>
+#include <types/stats.h>
+#include <proto/applet.h>
#include <proto/arg.h>
+#include <proto/cli.h>
#include <proto/map.h>
#include <proto/pattern.h>
+#include <proto/stream_interface.h>
#include <proto/sample.h>
/* Parse an IPv4 or IPv6 address and store it into the sample.
return 1;
}
+/* This function is used with map and acl management. It permits to browse
+ * each reference. The variable <getnext> must contain the current node,
+ * <end> point to the root node and the <flags> permit to filter required
+ * nodes.
+ */
+static inline
+struct pat_ref *pat_list_get_next(struct pat_ref *getnext, struct list *end,
+ unsigned int flags)
+{
+ struct pat_ref *ref = getnext;
+
+ while (1) {
+
+ /* Get next list entry. */
+ ref = LIST_NEXT(&ref->list, struct pat_ref *, list);
+
+ /* If the entry is the last of the list, return NULL. */
+ if (&ref->list == end)
+ return NULL;
+
+ /* If the entry match the flag, return it. */
+ if (ref->flags & flags)
+ return ref;
+ }
+}
+
+static inline
+struct pat_ref *pat_ref_lookup_ref(const char *reference)
+{
+ int id;
+ char *error;
+
+ /* If the reference starts by a '#', this is numeric id. */
+ if (reference[0] == '#') {
+ /* Try to convert the numeric id. If the conversion fails, the lookup fails. */
+ id = strtol(reference + 1, &error, 10);
+ if (*error != '\0')
+ return NULL;
+
+ /* Perform the unique id lookup. */
+ return pat_ref_lookupid(id);
+ }
+
+ /* Perform the string lookup. */
+ return pat_ref_lookup(reference);
+}
+
+/* This function is used with map and acl management. It permits to browse
+ * each reference.
+ */
+static inline
+struct pattern_expr *pat_expr_get_next(struct pattern_expr *getnext, struct list *end)
+{
+ struct pattern_expr *expr;
+ expr = LIST_NEXT(&getnext->list, struct pattern_expr *, list);
+ if (&expr->list == end)
+ return NULL;
+ return expr;
+}
+
+static int cli_io_handler_pat_list(struct appctx *appctx)
+{
+ struct stream_interface *si = appctx->owner;
+
+ switch (appctx->st2) {
+
+ case STAT_ST_INIT:
+ /* Init to the first entry. The list cannot be change */
+ appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.ref->head,
+ struct pat_ref_elt *, list);
+ if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
+ appctx->ctx.map.elt = NULL;
+ appctx->st2 = STAT_ST_LIST;
+ /* fall through */
+
+ case STAT_ST_LIST:
+ while (appctx->ctx.map.elt) {
+ chunk_reset(&trash);
+
+ /* build messages */
+ if (appctx->ctx.map.elt->sample)
+ chunk_appendf(&trash, "%p %s %s\n",
+ appctx->ctx.map.elt, appctx->ctx.map.elt->pattern,
+ appctx->ctx.map.elt->sample);
+ else
+ chunk_appendf(&trash, "%p %s\n",
+ appctx->ctx.map.elt, appctx->ctx.map.elt->pattern);
+
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ /* let's try again later from this stream. We add ourselves into
+ * this stream's users so that it can remove us upon termination.
+ */
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* get next list entry and check the end of the list */
+ appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.elt->list,
+ struct pat_ref_elt *, list);
+ if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
+ break;
+ }
+
+ appctx->st2 = STAT_ST_FIN;
+ /* fall through */
+
+ default:
+ appctx->st2 = STAT_ST_FIN;
+ return 1;
+ }
+}
+
+static int cli_io_handler_pats_list(struct appctx *appctx)
+{
+ struct stream_interface *si = appctx->owner;
+
+ switch (appctx->st2) {
+ case STAT_ST_INIT:
+ /* Display the column headers. If the message cannot be sent,
+ * quit the fucntion with returning 0. The function is called
+ * later and restart at the state "STAT_ST_INIT".
+ */
+ chunk_reset(&trash);
+ chunk_appendf(&trash, "# id (file) description\n");
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* Now, we start the browsing of the references lists.
+ * Note that the following call to LIST_ELEM return bad pointer. The only
+ * available field of this pointer is <list>. It is used with the function
+ * pat_list_get_next() for retruning 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);
+ appctx->st2 = STAT_ST_LIST;
+ /* fall through */
+
+ case STAT_ST_LIST:
+ while (appctx->ctx.map.ref) {
+ chunk_reset(&trash);
+
+ /* Build messages. If the reference is used by another category than
+ * the listed categorie, display the information in the massage.
+ */
+ chunk_appendf(&trash, "%d (%s) %s\n", appctx->ctx.map.ref->unique_id,
+ appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "",
+ appctx->ctx.map.ref->display);
+
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ /* let's try again later from this stream. We add ourselves into
+ * this stream's users so that it can remove us upon termination.
+ */
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* 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);
+ }
+
+ appctx->st2 = STAT_ST_FIN;
+ /* fall through */
+
+ default:
+ appctx->st2 = STAT_ST_FIN;
+ return 1;
+ }
+ return 0;
+}
+
+static int cli_io_handler_map_lookup(struct appctx *appctx)
+{
+ struct stream_interface *si = appctx->owner;
+ struct sample sample;
+ struct pattern *pat;
+ int match_method;
+
+ 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);
+ appctx->st2 = STAT_ST_LIST;
+ /* fall through */
+
+ case STAT_ST_LIST:
+ /* for each lookup type */
+ while (appctx->ctx.map.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.len = appctx->ctx.map.chunk.len;
+ sample.data.u.str.str = appctx->ctx.map.chunk.str;
+ 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);
+ 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])
+ break;
+ if (match_method >= PAT_MATCH_NUM)
+ chunk_appendf(&trash, "type=unknown(%p)", appctx->ctx.map.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)
+ 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)
+ chunk_appendf(&trash, ", found=no");
+ else
+ chunk_appendf(&trash, ", match=no");
+ }
+
+ /* Display match and match info */
+ else {
+ /* display match */
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+ chunk_appendf(&trash, ", found=yes");
+ else
+ chunk_appendf(&trash, ", match=yes");
+
+ /* display index mode */
+ if (pat->sflags & PAT_SF_TREE)
+ chunk_appendf(&trash, ", idx=tree");
+ else
+ chunk_appendf(&trash, ", idx=list");
+
+ /* display pattern */
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
+ if (pat->ref && pat->ref->pattern)
+ chunk_appendf(&trash, ", key=\"%s\"", pat->ref->pattern);
+ else
+ chunk_appendf(&trash, ", key=unknown");
+ }
+ else {
+ if (pat->ref && pat->ref->pattern)
+ chunk_appendf(&trash, ", pattern=\"%s\"", pat->ref->pattern);
+ else
+ chunk_appendf(&trash, ", pattern=unknown");
+ }
+
+ /* display return value */
+ if (appctx->ctx.map.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]);
+ else
+ chunk_appendf(&trash, ", value=none");
+ }
+ }
+
+ chunk_appendf(&trash, "\n");
+
+ /* display response */
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ /* let's try again later from this stream. We add ourselves into
+ * this stream's users so that it can remove us upon termination.
+ */
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* get next entry */
+ appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr,
+ &appctx->ctx.map.ref->pat);
+ }
+
+ appctx->st2 = STAT_ST_FIN;
+ /* fall through */
+
+ default:
+ appctx->st2 = STAT_ST_FIN;
+ free(appctx->ctx.map.chunk.str);
+ return 1;
+ }
+}
+
+static void cli_release_mlook(struct appctx *appctx)
+{
+ free(appctx->ctx.map.chunk.str);
+ appctx->ctx.map.chunk.str = NULL;
+}
+
+
+static int cli_parse_get_map(char **args, struct appctx *appctx, void *private)
+{
+ 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;
+ else
+ appctx->ctx.map.display_flags = PAT_REF_ACL;
+
+ /* No parameter. */
+ if (!*args[2] || !*args[3]) {
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+ appctx->ctx.cli.msg = "Missing map identifier and/or key.\n";
+ else
+ appctx->ctx.cli.msg = "Missing ACL identifier and/or key.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* 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)
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ else
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* copy input string. The string must be allocated because
+ * it may be used over multiple iterations. It's released
+ * at the end and upon abort anyway.
+ */
+ appctx->ctx.map.chunk.len = strlen(args[3]);
+ appctx->ctx.map.chunk.size = appctx->ctx.map.chunk.len + 1;
+ appctx->ctx.map.chunk.str = strdup(args[3]);
+ if (!appctx->ctx.map.chunk.str) {
+ appctx->ctx.cli.msg = "Out of memory error.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ return 0;
+ }
+ return 1;
+}
+
+static int cli_parse_show_map(char **args, struct appctx *appctx, void *private)
+{
+ if (strcmp(args[1], "map") == 0 ||
+ strcmp(args[1], "acl") == 0) {
+
+ /* Set ACL or MAP flags. */
+ if (args[1][0] == 'm')
+ appctx->ctx.map.display_flags = PAT_REF_MAP;
+ else
+ appctx->ctx.map.display_flags = PAT_REF_ACL;
+
+ /* no parameter: display all map available */
+ if (!*args[2]) {
+ appctx->st2 = STAT_ST_INIT;
+ appctx->st0 = STAT_CLI_O_CUSTOM;
+ appctx->io_handler = cli_io_handler_pats_list;
+ return 0;
+ }
+
+ /* 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)
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ else
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ appctx->st2 = STAT_ST_INIT;
+ appctx->st0 = STAT_CLI_O_CUSTOM;
+ appctx->io_handler = cli_io_handler_pat_list;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int cli_parse_set_map(char **args, struct appctx *appctx, void *private)
+{
+ if (strcmp(args[1], "map") == 0) {
+ char *err;
+
+ /* Set flags. */
+ appctx->ctx.map.display_flags = PAT_REF_MAP;
+
+ /* Expect three parameters: map name, key and new value. */
+ if (!*args[2] || !*args[3] || !*args[4]) {
+ appctx->ctx.cli.msg = "'set map' expects three parameters: map identifier, key and value.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Lookup the reference in the maps. */
+ appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
+ if (!appctx->ctx.map.ref) {
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* If the entry identifier start with a '#', it is considered as
+ * pointer id
+ */
+ if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
+ struct pat_ref_elt *ref;
+ long long int conv;
+ char *error;
+
+ /* Convert argument to integer value. */
+ conv = strtoll(&args[3][1], &error, 16);
+ if (*error != '\0') {
+ appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Convert and check integer to pointer. */
+ ref = (struct pat_ref_elt *)(long)conv;
+ if ((long long int)(long)ref != conv) {
+ appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Try to delete the entry. */
+ err = NULL;
+ if (!pat_ref_set_by_id(appctx->ctx.map.ref, ref, args[4], &err)) {
+ if (err)
+ memprintf(&err, "%s.\n", err);
+ appctx->ctx.cli.err = err;
+ appctx->st0 = STAT_CLI_PRINT_FREE;
+ return 1;
+ }
+ }
+ else {
+ /* Else, use the entry identifier as pattern
+ * string, and update the value.
+ */
+ err = NULL;
+ if (!pat_ref_set(appctx->ctx.map.ref, args[3], args[4], &err)) {
+ if (err)
+ memprintf(&err, "%s.\n", err);
+ appctx->ctx.cli.err = err;
+ appctx->st0 = STAT_CLI_PRINT_FREE;
+ return 1;
+ }
+ }
+
+ /* The set is done, send message. */
+ appctx->st0 = STAT_CLI_PROMPT;
+ return 0;
+ }
+ return 1;
+}
+
+static int cli_parse_add_map(char **args, struct appctx *appctx, void *private)
+{
+ if (strcmp(args[1], "map") == 0 ||
+ strcmp(args[1], "acl") == 0) {
+ int ret;
+ char *err;
+
+ /* Set flags. */
+ if (args[1][0] == 'm')
+ appctx->ctx.map.display_flags = PAT_REF_MAP;
+ else
+ appctx->ctx.map.display_flags = PAT_REF_ACL;
+
+ /* If the keywork is "map", we expect three parameters, if it
+ * is "acl", we expect only two parameters
+ */
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
+ if (!*args[2] || !*args[3] || !*args[4]) {
+ appctx->ctx.cli.msg = "'add map' expects three parameters: map identifier, key and value.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+ else {
+ if (!*args[2] || !*args[3]) {
+ appctx->ctx.cli.msg = "'add acl' expects two parameters: ACL identifier and pattern.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+
+ /* 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)
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ else
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* 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)) {
+ appctx->ctx.cli.msg = "This ACL is shared with a map containing samples. "
+ "You must use the command 'add map' to add values.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Add value. */
+ err = NULL;
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+ ret = pat_ref_add(appctx->ctx.map.ref, args[3], args[4], &err);
+ else
+ ret = pat_ref_add(appctx->ctx.map.ref, args[3], NULL, &err);
+ if (!ret) {
+ if (err)
+ memprintf(&err, "%s.\n", err);
+ appctx->ctx.cli.err = err;
+ appctx->st0 = STAT_CLI_PRINT_FREE;
+ return 1;
+ }
+
+ /* The add is done, send message. */
+ appctx->st0 = STAT_CLI_PROMPT;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int cli_parse_del_map(char **args, struct appctx *appctx, void *private)
+{
+ if (args[1][0] == 'm')
+ appctx->ctx.map.display_flags = PAT_REF_MAP;
+ else
+ appctx->ctx.map.display_flags = PAT_REF_ACL;
+
+ /* Expect two parameters: map name and key. */
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
+ if (!*args[2] || !*args[3]) {
+ appctx->ctx.cli.msg = "This command expects two parameters: map identifier and key.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+
+ else {
+ if (!*args[2] || !*args[3]) {
+ appctx->ctx.cli.msg = "This command expects two parameters: ACL identifier and key.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+
+ /* 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)) {
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* If the entry identifier start with a '#', it is considered as
+ * pointer id
+ */
+ if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
+ struct pat_ref_elt *ref;
+ long long int conv;
+ char *error;
+
+ /* Convert argument to integer value. */
+ conv = strtoll(&args[3][1], &error, 16);
+ if (*error != '\0') {
+ appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Convert and check integer to pointer. */
+ ref = (struct pat_ref_elt *)(long)conv;
+ if ((long long int)(long)ref != conv) {
+ appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Try to delete the entry. */
+ if (!pat_ref_delete_by_id(appctx->ctx.map.ref, ref)) {
+ /* The entry is not found, send message. */
+ appctx->ctx.cli.msg = "Key not found.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+ else {
+ /* Else, use the entry identifier as pattern
+ * string and try to delete the entry.
+ */
+ if (!pat_ref_delete(appctx->ctx.map.ref, args[3])) {
+ /* The entry is not found, send message. */
+ appctx->ctx.cli.msg = "Key not found.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+
+ /* The deletion is done, send message. */
+ appctx->st0 = STAT_CLI_PROMPT;
+ return 1;
+}
+
+
+static int cli_parse_clear_map(char **args, struct appctx *appctx, void *private)
+{
+ if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
+ /* Set ACL or MAP flags. */
+ if (args[1][0] == 'm')
+ appctx->ctx.map.display_flags = PAT_REF_MAP;
+ else
+ appctx->ctx.map.display_flags = PAT_REF_ACL;
+
+ /* no parameter */
+ if (!*args[2]) {
+ if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+ appctx->ctx.cli.msg = "Missing map identifier.\n";
+ else
+ appctx->ctx.cli.msg = "Missing ACL identifier.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* 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)
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
+ else
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ /* Clear all. */
+ pat_ref_prune(appctx->ctx.map.ref);
+
+ /* return response */
+ appctx->st0 = STAT_CLI_PROMPT;
+ return 1;
+ }
+ return 0;
+}
+
+/* register cli keywords */
+
+static struct cli_kw_list cli_kws = {{ },{
+ { { "add", "acl", NULL }, "add acl : add acl entry", cli_parse_add_map, NULL },
+ { { "clear", "acl", NULL }, "clear acl <id> : clear the content of this acl", cli_parse_clear_map, NULL },
+ { { "del", "acl", NULL }, "del acl : delete acl entry", cli_parse_del_map, NULL },
+ { { "get", "acl", NULL }, "get acl : report the patterns matching a sample for an ACL", cli_parse_get_map, cli_io_handler_map_lookup, cli_release_mlook },
+ { { "show", "acl", NULL }, "show acl [id] : report available acls or dump an acl's contents", cli_parse_show_map, NULL },
+ { { "add", "map", NULL }, "add map : add map entry", cli_parse_add_map, NULL },
+ { { "clear", "map", NULL }, "clear map <id> : clear the content of this map", cli_parse_clear_map, NULL },
+ { { "del", "map", NULL }, "del map : delete map entry", cli_parse_del_map, NULL },
+ { { "get", "map", NULL }, "get map : report the keys and values matching a sample for a map", cli_parse_get_map, NULL },
+ { { "set", "map", NULL }, "set map : modify map entry", cli_parse_set_map, NULL },
+ { { "show", "map", NULL }, "show map [id] : report available maps or dump a map's contents", cli_parse_show_map, NULL },
+ { { NULL }, NULL, NULL, NULL }
+}};
+
+
/* Note: must not be declared <const> as its list will be overwritten
*
* For the map_*_int keywords, the output is declared as SMP_T_UINT, but the converter function
{
/* register format conversion keywords */
sample_register_convs(&sample_conv_kws);
+ cli_register_kw(&cli_kws);
}