* The function returns 1 if the processing is ok, return 0
* if the parser fails, with <err> message filled.
*/
-int pattern_register(struct pattern_head *head, char *reference, int refflags, const char *arg, struct sample_storage *smp, int patflags, char **err);
+int pattern_register(struct pattern_head *head, int unique_id, int refflags, const char *arg, struct sample_storage *smp, int patflags, char **err);
void pattern_finalize_config(void);
/* return the PAT_MATCH_* index for match name "name", or < 0 if not found */
* pattern_ref manipulation.
*/
struct pat_ref *pat_ref_lookup(const char *reference);
+struct pat_ref *pat_ref_lookupid(int unique_id);
struct pat_ref *pat_ref_new(const char *reference, unsigned int flags);
+struct pat_ref *pat_ref_newid(int unique_id, unsigned int flags);
int pat_ref_append(struct pat_ref *ref, char *pattern, char *sample, int line);
int pat_ref_add(struct pat_ref *ref, const char *pattern, const char *sample, char **err);
int pat_ref_set(struct pat_ref *ref, const char *pattern, const char *sample);
struct list list; /* Used to chain refs. */
unsigned int flags; /* flags PAT_REF_*. */
char *reference; /* The reference name. */
+ int unique_id; /* Each pattern reference have unique id. */
struct list head; /* The head of the list of struct pat_ref_elt. */
struct list pat; /* The head of the list of struct pattern_expr. */
};
}
}
- if (!pattern_register(&expr->pat, NULL, PAT_REF_ACL, arg, NULL, patflags, err))
+ if (!pattern_register(&expr->pat, -1, PAT_REF_ACL, arg, NULL, patflags, err))
goto out_free_expr;
args++;
}
}
}
+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.
*/
}
/* lookup into the refs and check the map flag */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ 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 <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
/* lookup into the refs and check the map flag */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ 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 <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
/* lookup into the maps */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ 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 <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
/* Lookup the reference in the maps. */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
if (!appctx->ctx.map.ref) {
- appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
/* Lookup the reference in the maps. */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ 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 <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
/* Lookup for the reference. */
- appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+ 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 <name>.\n";
+ appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
else
- appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+ appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
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 (name)\n");
+ if (bi_putchk(si->ib, &trash) == -1)
+ return 0;
/* Now, we start the browsing of the references lists.
* Note that the following call to LIST_ELEM return bad pointer. The only
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.
*/
- if ((appctx->ctx.map.display_flags & PAT_REF_MAP) &&
- (appctx->ctx.map.ref->flags & PAT_REF_ACL)) {
- chunk_appendf(&trash, "%s (also used by an ACL)\n",
- appctx->ctx.map.ref->reference);
+ chunk_appendf(&trash, "%d (%s)", appctx->ctx.map.ref->unique_id,
+ appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "");
+
+ if (appctx->ctx.map.display_flags & PAT_REF_MAP) {
+ if (appctx->ctx.map.ref->flags & PAT_REF_ACL)
+ chunk_appendf(&trash, " - also used by an ACL");
}
- else if ((appctx->ctx.map.display_flags & PAT_REF_ACL) &&
- (appctx->ctx.map.ref->flags & PAT_REF_MAP)) {
- chunk_appendf(&trash, "%s (also used by a map)\n",
- appctx->ctx.map.ref->reference);
+ else {
+ if (appctx->ctx.map.ref->flags & PAT_REF_MAP)
+ chunk_appendf(&trash, " - also used by a map");
}
- else
- chunk_appendf(&trash, "%s\n", appctx->ctx.map.ref->reference);
+ chunk_appendf(&trash, "\n");
if (bi_putchk(si->ib, &trash) == -1) {
/* let's try again later from this session. We add ourselves into
#include <proto/hdr_idx.h>
#include <proto/listener.h>
#include <proto/log.h>
+#include <proto/pattern.h>
#include <proto/protocol.h>
#include <proto/proto_http.h>
#include <proto/proxy.h>
exit(1);
}
+ pattern_finalize_config();
+
err_code |= check_config_validity();
if (err_code & (ERR_ABORT|ERR_FATAL)) {
Alert("Fatal errors found in configuration.\n");
* value as string form.
*
* This is used with modifiable ACL and MAPS
+ *
+ * The pattern reference are stored with two identifiers: the unique_id and
+ * the reference.
+ *
+ * The reference identify a file. Each file with the same name point to the
+ * same reference. We can register many times one file. If the file is modified,
+ * all his dependencies are also modified. The reference can be used with map or
+ * acl.
+ *
+ * The unique_id identify inline acl. The unique id is unique for each acl.
+ * You cannot force the same id in the configuration file, because this repoort
+ * an error.
+ *
+ * A particular case appears if the filename is a number. In this case, the
+ * unique_id is set with the number represented by the filename and the
+ * reference is also set. This method prevent double unique_id.
+ *
*/
/* This function lookup for reference. If the reference is found, they return
struct pat_ref *ref;
list_for_each_entry(ref, &pattern_reference, list)
- if (strcmp(reference, ref->reference) == 0)
+ if (ref->reference && strcmp(reference, ref->reference) == 0)
+ return ref;
+ return NULL;
+}
+
+/* This function lookup for unique id. If the reference is found, they return
+ * pointer to the struct pat_ref, else return NULL.
+ */
+struct pat_ref *pat_ref_lookupid(int unique_id)
+{
+ struct pat_ref *ref;
+
+ list_for_each_entry(ref, &pattern_reference, list)
+ if (ref->unique_id == unique_id)
return ref;
return NULL;
}
}
ref->flags = flags;
+ ref->unique_id = -1;
+
+ LIST_INIT(&ref->head);
+ LIST_INIT(&ref->pat);
+
+ LIST_ADDQ(&pattern_reference, &ref->list);
+
+ return ref;
+}
+
+/* This function create new reference. <unique_id> is the unique id. If
+ * the value of <unique_id> is -1, the unique id is calculated later.
+ * <flags> are PAT_REF_*. /!\ The reference is not checked, and must
+ * be unique. The user must check the reference with "pat_ref_lookup()"
+ * or pat_ref_lookupid before calling this function. If the function
+ * fail, it return NULL, else return new struct pat_ref.
+ */
+struct pat_ref *pat_ref_newid(int unique_id, unsigned int flags)
+{
+ struct pat_ref *ref;
+
+ ref = malloc(sizeof(*ref));
+ if (!ref)
+ return NULL;
+
+ ref->reference = NULL;
+ ref->flags = flags;
+ ref->unique_id = unique_id;
LIST_INIT(&ref->head);
LIST_INIT(&ref->pat);
* return -2 if out of memory
*/
int pattern_register(struct pattern_head *head,
- char *reference, int refflags,
+ int unique_id, int refflags,
const char *arg,
struct sample_storage *smp,
int patflags, char **err)
struct pattern_expr *expr;
struct pat_ref *ref;
- /* If reference is set, look up for existing reference. If the
- * reference is not found, create it.
- */
- if (reference) {
- ref = pat_ref_lookup(reference);
- if (!ref) {
- ref = pat_ref_new(reference, refflags);
- if (!ref) {
- memprintf(err, "out of memory");
- return 0;
- }
+ /* Look if the unique id already exists. If exists, abort the acl creation. */
+ if (unique_id >= 0) {
+ ref = pat_ref_lookupid(unique_id);
+ if (ref) {
+ memprintf(err, "The unique id \"%d\" is already used.", unique_id);
+ return 0;
}
}
- else
- ref = NULL;
- /* look for reference or create it */
- expr = pattern_lookup_expr(head, ref);
- if (!expr) {
- expr = pattern_new_expr(head, ref, err);
- if (!expr)
- return 0;
+ /* Create new reference. */
+ ref = pat_ref_newid(unique_id, refflags);
+ if (!ref) {
+ memprintf(err, "out of memory");
+ return 0;
}
+ /* create new pattern_expr. */
+ expr = pattern_new_expr(head, ref, err);
+ if (!expr)
+ return 0;
+
/* Index value. */
return pattern_add(expr, arg, smp, patflags, err);
}
struct pat_ref *ref;
struct pattern_expr *expr;
- /* Look for existing reference. If the reference doesn't exists,
- * create it and load file.
- */
+ /* Lookup for the existing reference. */
ref = pat_ref_lookup(filename);
+
+ /* If the reference doesn't exists, create it and load associated file. */
if (!ref) {
ref = pat_ref_new(filename, refflags);
if (!ref) {
expr->pat_head->delete(expr, &pattern);
return 1;
}
+
+/* This function finalize the configuration parsing. Its set all the
+ * automatic ids
+ */
+void pattern_finalize_config(void)
+{
+ int i = 0;
+ struct pat_ref *ref, *ref2, *ref3;
+ struct list pr = LIST_HEAD_INIT(pr);
+
+ list_for_each_entry(ref, &pattern_reference, list) {
+ if (ref->unique_id == -1) {
+ /* Look for the first free id. */
+ while (1) {
+ list_for_each_entry(ref2, &pattern_reference, list) {
+ if (ref2->unique_id == i) {
+ i++;
+ break;
+ }
+ }
+ if (&ref2->list == &pattern_reference);
+ break;
+ }
+
+ /* Uses the unique id and increment it for the next entry. */
+ ref->unique_id = i;
+ i++;
+ }
+ }
+
+ /* This sort the reference list by id. */
+ list_for_each_entry_safe(ref, ref2, &pattern_reference, list) {
+ LIST_DEL(&ref->list);
+ list_for_each_entry(ref3, &pr, list) {
+ if (ref->unique_id < ref3->unique_id) {
+ LIST_ADDQ(&ref3->list, &ref->list);
+ break;
+ }
+ }
+ if (&ref3->list == &pr)
+ LIST_ADDQ(&pr, &ref->list);
+ }
+
+ /* swap root */
+ LIST_ADD(&pr, &pattern_reference);
+ LIST_DEL(&pr);
+}