diff --git a/include/proto/pattern.h b/include/proto/pattern.h index 9b7c40e31..830630b24 100644 --- a/include/proto/pattern.h +++ b/include/proto/pattern.h @@ -40,7 +40,7 @@ * The function returns 1 if the processing is ok, return 0 * if the parser fails, with 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 */ @@ -197,7 +197,9 @@ struct pattern *pat_match_reg(struct sample *smp, struct pattern_expr *expr, int * 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); diff --git a/include/types/pattern.h b/include/types/pattern.h index dfee1097d..156e57bbf 100644 --- a/include/types/pattern.h +++ b/include/types/pattern.h @@ -97,6 +97,7 @@ struct pat_ref { 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. */ }; diff --git a/src/acl.c b/src/acl.c index d4d1cfbd3..4e3321357 100644 --- a/src/acl.c +++ b/src/acl.c @@ -598,7 +598,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list * } } - 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++; } diff --git a/src/dumpstats.c b/src/dumpstats.c index 57a9fc51f..f6768c920 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -982,6 +982,27 @@ struct pat_ref *pat_list_get_next(struct pat_ref *getnext, struct list *end, } } +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. */ @@ -1123,13 +1144,13 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; else - appctx->ctx.cli.msg = "Unknown ACL identifier. Please use .\n"; + appctx->ctx.cli.msg = "Unknown ACL identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -1222,13 +1243,13 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; else - appctx->ctx.cli.msg = "Unknown ACL identifier. Please use .\n"; + appctx->ctx.cli.msg = "Unknown ACL identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -1293,12 +1314,12 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; else - appctx->ctx.cli.msg = "Unknown ACL identifier. Please use .\n"; + appctx->ctx.cli.msg = "Unknown ACL identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -1605,9 +1626,9 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -1872,10 +1893,10 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -1929,12 +1950,12 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } /* 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 .\n"; + appctx->ctx.cli.msg = "Unknown map identifier. Please use # or .\n"; else - appctx->ctx.cli.msg = "Unknown ACL identifier. Please use .\n"; + appctx->ctx.cli.msg = "Unknown ACL identifier. Please use # or .\n"; appctx->st0 = STAT_CLI_PRINT; return 1; } @@ -4736,6 +4757,14 @@ static int stats_pats_list(struct stream_interface *si) 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 @@ -4750,24 +4779,23 @@ static int stats_pats_list(struct stream_interface *si) 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 diff --git a/src/haproxy.c b/src/haproxy.c index 2b83c62a4..fb8c8a135 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -693,6 +694,8 @@ void init(int argc, char **argv) exit(1); } + pattern_finalize_config(); + err_code |= check_config_validity(); if (err_code & (ERR_ABORT|ERR_FATAL)) { Alert("Fatal errors found in configuration.\n"); diff --git a/src/pattern.c b/src/pattern.c index e35a59d2b..862504890 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -1562,6 +1562,23 @@ void pattern_init_head(struct pattern_head *head) * 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 @@ -1572,7 +1589,20 @@ struct pat_ref *pat_ref_lookup(const char *reference) 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; } @@ -1663,6 +1693,34 @@ struct pat_ref *pat_ref_new(const char *reference, unsigned int flags) } 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. is the unique id. If + * the value of is -1, the unique id is calculated later. + * 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); @@ -1961,7 +2019,7 @@ struct pattern_expr *pattern_new_expr(struct pattern_head *head, struct pat_ref * 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) @@ -1969,30 +2027,27 @@ int pattern_register(struct pattern_head *head, 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); } @@ -2060,10 +2115,10 @@ int pattern_read_from_file(struct pattern_head *head, unsigned int refflags, 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) { @@ -2170,3 +2225,50 @@ int pattern_delete(const char *key, struct pattern_expr *expr, char **err) 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); +}