diff --git a/include/haproxy/sink-t.h b/include/haproxy/sink-t.h index 990aa72d6..f72a4e12a 100644 --- a/include/haproxy/sink-t.h +++ b/include/haproxy/sink-t.h @@ -31,9 +31,10 @@ * - ring buffer, readable from CLI */ enum sink_type { - SINK_TYPE_NEW, // not yet initialized - SINK_TYPE_FD, // events sent to a file descriptor - SINK_TYPE_BUFFER, // events sent to a ring buffer + SINK_TYPE_FORWARD_DECLARED, // was searched using sink_find_early(), is expected to exist by some component + SINK_TYPE_NEW, // not yet initialized + SINK_TYPE_FD, // events sent to a file descriptor + SINK_TYPE_BUFFER, // events sent to a ring buffer }; struct sink_forward_target { @@ -50,7 +51,11 @@ struct sink_forward_target { struct sink { struct list sink_list; // position in the sink list char *name; // sink name - char *desc; // sink description + char *desc; /* sink description: + * when forward-declared, holds info about where the + * sink was first forward declared, else holds actual + * sink description + */ char *store; // backing-store file when buffer enum log_fmt fmt; // format expected by the sink enum sink_type type; // type of storage diff --git a/include/haproxy/sink.h b/include/haproxy/sink.h index bdc84475b..ebf7c66d4 100644 --- a/include/haproxy/sink.h +++ b/include/haproxy/sink.h @@ -31,6 +31,7 @@ extern struct list sink_list; extern struct proxy *sink_proxies_list; struct sink *sink_find(const char *name); +struct sink *sink_find_early(const char *name, const char *from, const char *file, int line); struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt, int fd); ssize_t __sink_write(struct sink *sink, struct log_header hdr, size_t maxlen, const struct ist msg[], size_t nmsg); diff --git a/src/sink.c b/src/sink.c index 711233793..0b9518388 100644 --- a/src/sink.c +++ b/src/sink.c @@ -46,7 +46,7 @@ struct proxy *sink_proxies_list; struct sink *cfg_sink; -struct sink *sink_find(const char *name) +static struct sink *_sink_find(const char *name) { struct sink *sink; @@ -56,6 +56,63 @@ struct sink *sink_find(const char *name) return NULL; } +/* returns sink if it really exists */ +struct sink *sink_find(const char *name) +{ + struct sink *sink; + + sink = _sink_find(name); + if (sink && sink->type != SINK_TYPE_FORWARD_DECLARED) + return sink; + return NULL; +} + +/* Similar to sink_find(), but intended to be used during config parsing: + * tries to resolve sink name, if it fails, creates the sink and marks + * it as forward-declared and hope that it will be defined later. + * + * The caller has to identify itself using , and in + * order to report precise error messages in the event that the sink is + * never defined later (only the first misuse will be considered). + * + * It returns the sink on success and NULL on failure (memory error) + */ +struct sink *sink_find_early(const char *name, const char *from, const char *file, int line) +{ + struct sink *sink; + + /* not expected to be used during runtime */ + BUG_ON(!(global.mode & MODE_STARTING)); + + sink = _sink_find(name); + if (sink) + return sink; + + /* not found, try to forward-declare it */ + sink = calloc(1, sizeof(*sink)); + if (!sink) + return NULL; + + sink->name = strdup(name); + if (!sink->name) + goto err; + + memprintf(&sink->desc, "parsing [%s:%d] : %s", file, line, from); + if (!sink->desc) + goto err; + + sink->type = SINK_TYPE_FORWARD_DECLARED; + LIST_APPEND(&sink_list, &sink->sink_list); + + return sink; + + err: + ha_free(&sink->name); + ha_free(&sink->desc); + ha_free(&sink); + return NULL; +} + /* creates a new sink and adds it to the list, it's still generic and not fully * initialized. Returns NULL on allocation failure. If another one already * exists with the same name, it will be returned. The caller can detect it as @@ -64,12 +121,19 @@ struct sink *sink_find(const char *name) static struct sink *__sink_new(const char *name, const char *desc, int fmt) { struct sink *sink; + uint8_t _new = 0; - sink = sink_find(name); - if (sink) + sink = _sink_find(name); + if (sink) { + if (sink->type == SINK_TYPE_FORWARD_DECLARED) { + ha_free(&sink->desc); // free previous desc + goto forward_declared; + } goto end; + } sink = calloc(1, sizeof(*sink)); + _new = 1; if (!sink) goto end; @@ -77,6 +141,7 @@ static struct sink *__sink_new(const char *name, const char *desc, int fmt) if (!sink->name) goto err; + forward_declared: sink->desc = strdup(desc); if (!sink->desc) goto err; @@ -87,7 +152,8 @@ static struct sink *__sink_new(const char *name, const char *desc, int fmt) /* address will be filled by the caller if needed */ sink->ctx.fd = -1; sink->ctx.dropped = 0; - LIST_APPEND(&sink_list, &sink->sink_list); + if (_new) + LIST_APPEND(&sink_list, &sink->sink_list); end: return sink; @@ -1329,6 +1395,23 @@ static void sink_init() sink_new_buf("buf0", "in-memory ring buffer", LOG_FORMAT_TIMED, 1048576); } +static int sink_postcheck() +{ + struct sink *sink; + + list_for_each_entry(sink, &sink_list, sink_list) { + if (sink->type == SINK_TYPE_FORWARD_DECLARED) { + /* sink wasn't upgraded to actual sink despite being + * forward-declared: it is an error (the sink doesn't + * really exist) + */ + ha_alert("%s: sink '%s' doesn't exist.\n", sink->desc, sink->name); + return ERR_ALERT | ERR_FATAL; + } + } + return ERR_NONE; +} + static void sink_deinit() { struct sink *sink, *sb; @@ -1338,6 +1421,7 @@ static void sink_deinit() } INITCALL0(STG_REGISTER, sink_init); +REGISTER_POST_CHECK(sink_postcheck); REGISTER_POST_DEINIT(sink_deinit); static struct cli_kw_list cli_kws = {{ },{