From af5a29d5f880c043d943c35b3c194eeb35c050e1 Mon Sep 17 00:00:00 2001 From: Thierry FOURNIER Date: Tue, 11 Mar 2014 14:29:22 +0100 Subject: [PATCH] MINOR: pattern: Each pattern is identified by unique id. 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 repport an error. The format of the acl and map listing through the "socket" has changed for displaying these new ids. --- include/proto/pattern.h | 4 +- include/types/pattern.h | 1 + src/acl.c | 2 +- src/dumpstats.c | 82 ++++++++++++++-------- src/haproxy.c | 3 + src/pattern.c | 150 +++++++++++++++++++++++++++++++++------- 6 files changed, 189 insertions(+), 53 deletions(-) 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); +}