mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Conf: use coroutine to read new config
This commit is contained in:
parent
642acc1b59
commit
4ec43aa137
@ -330,12 +330,6 @@ cf_hash(byte *c)
|
||||
return h;
|
||||
}
|
||||
|
||||
static void
|
||||
cf_init_state(struct cf_context *ctx, struct conf_state *cs)
|
||||
{
|
||||
cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
|
||||
}
|
||||
|
||||
struct conf_state *
|
||||
cf_new_state(struct cf_context *ctx, const char *name)
|
||||
{
|
||||
@ -344,7 +338,7 @@ cf_new_state(struct cf_context *ctx, const char *name)
|
||||
.name = cfg_strdup(name),
|
||||
.lino = 1,
|
||||
};
|
||||
cf_init_state(ctx, cs);
|
||||
cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
|
||||
return cs;
|
||||
}
|
||||
|
||||
@ -400,7 +394,7 @@ cf_init_kh(void)
|
||||
* parsing of a new input.
|
||||
*/
|
||||
struct cf_context *
|
||||
cf_new_context(int is_cli, struct conf_order *order)
|
||||
cf_new_context(struct conf_order *order)
|
||||
{
|
||||
struct cf_context *ctx = order->ctx = lp_allocz(order->new_config->mem, sizeof(struct cf_context));
|
||||
*ctx = (struct cf_context) {
|
||||
@ -412,10 +406,7 @@ cf_new_context(int is_cli, struct conf_order *order)
|
||||
cfx_lex_init_extra(ctx, &(ctx->yyscanner));
|
||||
struct yyguts_t *yyg = ctx->yyscanner;
|
||||
|
||||
cf_init_state(ctx, order->state);
|
||||
yy_switch_to_buffer(order->state->buffer, yyg);
|
||||
|
||||
if (is_cli)
|
||||
if (order->flags & CO_CLI)
|
||||
BEGIN(CLI);
|
||||
else
|
||||
BEGIN(INITIAL);
|
||||
|
125
conf/conf.c
125
conf/conf.c
@ -103,16 +103,42 @@ config_alloc(struct pool *pp, struct linpool *lp)
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
config_parse(struct conf_order *order)
|
||||
static void config_event_resume(void *arg)
|
||||
{
|
||||
DBG("Parsing configuration named `%s'\n", order->state->name);
|
||||
DBG("config event resume\n");
|
||||
struct cf_context *ctx = arg;
|
||||
coro_resume(ctx->coro);
|
||||
}
|
||||
|
||||
if (!order->new_config)
|
||||
order->new_config = config_alloc(order->pool, order->lp);
|
||||
static void config_event_cleanup(void *arg)
|
||||
{
|
||||
DBG("config event cleanup\n");
|
||||
struct cf_context *ctx = arg;
|
||||
struct conf_order *order = ctx->order;
|
||||
|
||||
struct cf_context *ctx = cf_new_context(0, order);
|
||||
int ret;
|
||||
rfree(ctx->coro);
|
||||
|
||||
cf_free_context(ctx);
|
||||
order->ctx = NULL;
|
||||
|
||||
if (order->flags & CO_CLI)
|
||||
{
|
||||
config_free(order->new_config);
|
||||
order->new_config = NULL;
|
||||
}
|
||||
|
||||
return order->cf_done(order);
|
||||
}
|
||||
|
||||
static void
|
||||
config_parse_coro(void *arg)
|
||||
{
|
||||
struct cf_context *ctx = arg;
|
||||
struct conf_order *order = ctx->order;
|
||||
DBG("%s parse coroutine started in %s mode\n",
|
||||
(order->flags & CO_CLI) ? "Cli" : "Conf",
|
||||
(order->flags & CO_SYNC) ? "sync" : "async"
|
||||
);
|
||||
|
||||
if (setjmp(ctx->jmpbuf))
|
||||
{
|
||||
@ -120,58 +146,80 @@ config_parse(struct conf_order *order)
|
||||
while (! order->cf_outclude(order))
|
||||
;
|
||||
|
||||
ret = 0;
|
||||
|
||||
config_free(ctx->new_config);
|
||||
order->new_config = NULL;
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sysdep_preconfig(ctx);
|
||||
protos_preconfig(ctx->new_config);
|
||||
rt_preconfig(ctx);
|
||||
cfx_parse(ctx, ctx->yyscanner);
|
||||
|
||||
if (EMPTY_LIST((ctx->new_config)->protos))
|
||||
if (!(order->flags & CO_CLI) && EMPTY_LIST(ctx->new_config->protos))
|
||||
cf_error(ctx, "No protocol is specified in the config file");
|
||||
|
||||
ret = 1;
|
||||
|
||||
cleanup:
|
||||
cf_free_context(ctx);
|
||||
order->ctx = NULL;
|
||||
return ret;
|
||||
if (order->flags & CO_SYNC)
|
||||
return;
|
||||
|
||||
DBG("config parse coroutine done, scheduling thread join\n");
|
||||
coro_done(ctx->ev_cleanup);
|
||||
bug("Resumed config when done.");
|
||||
}
|
||||
|
||||
int
|
||||
cli_parse(struct conf_order *order)
|
||||
void
|
||||
config_parse(struct conf_order *order)
|
||||
{
|
||||
DBG("Parsing command line\n");
|
||||
DBG("Parsing configuration\n");
|
||||
|
||||
struct config cc = {};
|
||||
cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config");
|
||||
cc.mem = order->lp ?: lp_new_default(cc.pool);
|
||||
if (!order->new_config)
|
||||
order->new_config = config_alloc(order->pool, order->lp);
|
||||
|
||||
order->new_config = &cc;
|
||||
pool *p = order->new_config->pool;
|
||||
|
||||
struct cf_context *ctx = cf_new_context(1, order);
|
||||
struct cf_context *ctx = cf_new_context(order);
|
||||
|
||||
cf_scan_bytes(ctx, order->buf, order->len);
|
||||
/* CLI does no preconfig */
|
||||
if (!(order->flags & CO_CLI))
|
||||
{
|
||||
sysdep_preconfig(ctx);
|
||||
protos_preconfig(ctx->new_config);
|
||||
rt_preconfig(ctx);
|
||||
}
|
||||
|
||||
int ok = 0;
|
||||
if (setjmp(ctx->jmpbuf))
|
||||
goto done;
|
||||
if (!(order->flags & CO_SYNC))
|
||||
{
|
||||
ctx->ev_resume = ev_new(p);
|
||||
ctx->ev_resume->hook = config_event_resume;
|
||||
ctx->ev_resume->data = ctx;
|
||||
|
||||
cfx_parse(ctx, ctx->yyscanner);
|
||||
ok = 1;
|
||||
ctx->ev_cleanup = ev_new(p);
|
||||
ctx->ev_cleanup->hook = config_event_cleanup;
|
||||
ctx->ev_cleanup->data = ctx;
|
||||
}
|
||||
|
||||
done:
|
||||
cf_free_context(ctx);
|
||||
config_free(&cc);
|
||||
order->new_config = NULL;
|
||||
order->ctx = NULL;
|
||||
return ok;
|
||||
if (order->flags & CO_FILENAME)
|
||||
if (order->cf_include)
|
||||
order->cf_include(order, order->buf, order->len);
|
||||
else
|
||||
bug("Include handler must be set to config from file");
|
||||
else
|
||||
cf_scan_bytes(ctx, order->buf, order->len);
|
||||
/* Warning: Return from include will fail badly if you start with a buffer.
|
||||
* Currently it's not supported to supply cf_include hook without CO_FILENAME flag.
|
||||
*/
|
||||
|
||||
if (order->flags & CO_SYNC)
|
||||
return config_parse_coro(ctx);
|
||||
|
||||
ctx->coro = coro_new(p, config_parse_coro, ctx);
|
||||
coro_resume(ctx->coro);
|
||||
}
|
||||
|
||||
void config_yield(struct cf_context *ctx)
|
||||
{
|
||||
DBG("Conf: Yield\n");
|
||||
ev_schedule(ctx->ev_resume);
|
||||
DBG("Conf: Yield resumed\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,6 +367,7 @@ config_done(void *unused UNUSED)
|
||||
int
|
||||
config_commit(struct config *c, int type, uint timeout)
|
||||
{
|
||||
ASSERT(type != RECONFIG_CHECK);
|
||||
if (shutting_down)
|
||||
{
|
||||
config_free(c);
|
||||
|
40
conf/conf.h
40
conf/conf.h
@ -59,18 +59,30 @@ struct conf_state {
|
||||
uint lino; /* Current line */
|
||||
};
|
||||
|
||||
enum conf_order_flag {
|
||||
CO_CLI = 1, /* Parse CLI, not regular config */
|
||||
CO_SYNC = 2, /* Run parser synchronously */
|
||||
CO_FILENAME = 4, /* Use the order buffer as filename */
|
||||
} PACKED;
|
||||
|
||||
/* This struct is meant to be inherited and customized by caller */
|
||||
struct conf_order {
|
||||
struct config *new_config; /* Store the allocated config here */
|
||||
resource r;
|
||||
struct config *new_config; /* Outputs the allocated config here */
|
||||
struct cf_context *ctx; /* Internal config context, do not set */
|
||||
struct conf_state *state;
|
||||
struct conf_state *state; /* Internal config state, do not set */
|
||||
|
||||
struct pool *pool; /* If set, use this resource pool */
|
||||
struct linpool *lp; /* If set, use this linpool */
|
||||
const char *buf;
|
||||
uint len;
|
||||
const char *buf; /* Buffer to parse or filename */
|
||||
uint len; /* Buffer length */
|
||||
enum conf_order_flag flags;
|
||||
|
||||
int (*cf_read_hook)(struct conf_order *order, byte *buf, uint max);
|
||||
void (*cf_include)(struct conf_order *order, char *name, uint len);
|
||||
void (*cf_include)(struct conf_order *order, const char *name, uint len);
|
||||
int (*cf_outclude)(struct conf_order *order);
|
||||
void (*cf_error)(struct conf_order *order, const char *msg, va_list args);
|
||||
void (*cf_done)(struct conf_order *order);
|
||||
};
|
||||
|
||||
/* Please don't use these variables in protocols. Use proto_config->global instead. */
|
||||
@ -82,25 +94,12 @@ extern struct config *config; /* Currently active configuration */
|
||||
* Arguments:
|
||||
* @order provides callbacks to read config files
|
||||
*
|
||||
* This function queues
|
||||
* Return value:
|
||||
* 1 on success; order->new_config is then set to the parsed config
|
||||
* 0 on fail; order->new_config is undefined
|
||||
**/
|
||||
int config_parse(struct conf_order *order);
|
||||
|
||||
/**
|
||||
* Parse CLI command
|
||||
*
|
||||
* Arguments:
|
||||
* @order provides callbacks to read command line
|
||||
*
|
||||
* Return value:
|
||||
* 1 on success
|
||||
* 0 on fail
|
||||
*
|
||||
* Parsed config is never kept, order->new_config should be zero after return.
|
||||
**/
|
||||
int cli_parse(struct conf_order *order);
|
||||
void config_parse(struct conf_order *order);
|
||||
|
||||
/** Callback for returning error from parser hooks */
|
||||
void cf_error(struct cf_context *, const char *msg, ...) NORET;
|
||||
@ -118,6 +117,7 @@ void order_shutdown(void);
|
||||
#define RECONFIG_HARD 1
|
||||
#define RECONFIG_SOFT 2
|
||||
#define RECONFIG_UNDO 3
|
||||
#define RECONFIG_CHECK 4
|
||||
|
||||
#define CONF_DONE 0
|
||||
#define CONF_PROGRESS 1
|
||||
|
@ -22,6 +22,7 @@ CF_HDR
|
||||
#include "nest/route.h"
|
||||
#include "nest/cli.h"
|
||||
#include "filter/filter.h"
|
||||
#include "lib/coroutine.h"
|
||||
|
||||
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
|
||||
|
||||
@ -33,6 +34,9 @@ struct config *new_config;
|
||||
jmp_buf jmpbuf;
|
||||
linpool *cfg_mem;
|
||||
struct conf_order *order;
|
||||
coroutine *coro;
|
||||
event *ev_resume;
|
||||
event *ev_cleanup;
|
||||
|
||||
CF_DEFINES
|
||||
|
||||
|
@ -27,7 +27,7 @@ union YYSTYPE;
|
||||
int cfx_lex(union YYSTYPE *, yyscan_t);
|
||||
|
||||
/* Config context alloc and free */
|
||||
struct cf_context *cf_new_context(int, struct conf_order *);
|
||||
struct cf_context *cf_new_context(struct conf_order *);
|
||||
void cf_free_context(struct cf_context *);
|
||||
|
||||
/* Lexer state alloc and free */
|
||||
|
@ -33,6 +33,7 @@ Reply codes of BIRD command-line interface
|
||||
0022 Undo scheduled
|
||||
0023 Evaluation of expression
|
||||
0024 Graceful restart status report
|
||||
0025 Reconfiguration rejected, another config not parsed yet
|
||||
|
||||
1000 BIRD version
|
||||
1001 Interface list
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "lib/lists.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Resource */
|
||||
|
||||
typedef struct resource {
|
||||
|
@ -442,6 +442,7 @@ cli_command(struct cli *c)
|
||||
.cf_error = cli_cmd_error,
|
||||
.lp = c->parser_pool,
|
||||
.pool = c->pool,
|
||||
.flags = CO_CLI | CO_SYNC,
|
||||
},
|
||||
.cli = c,
|
||||
};
|
||||
@ -451,7 +452,7 @@ cli_command(struct cli *c)
|
||||
|
||||
lp_flush(c->parser_pool);
|
||||
this_cli = c;
|
||||
cli_parse(&(o.co));
|
||||
config_parse(&(o.co));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -468,8 +469,6 @@ cli_event(void *data)
|
||||
c->async_msg_size < CLI_MAX_ASYNC_QUEUE)
|
||||
cli_copy_message(c);
|
||||
|
||||
cli_write_trigger(c);
|
||||
|
||||
if (c->state == CLI_STATE_YIELD ||
|
||||
c->state == CLI_STATE_WAIT_TX && !c->tx_pos)
|
||||
coro_resume(c->coro);
|
||||
|
@ -66,6 +66,7 @@ typedef struct cli {
|
||||
uint log_mask; /* Mask of allowed message levels */
|
||||
uint log_threshold; /* When free < log_threshold, store only important messages */
|
||||
uint async_msg_size; /* Total size of async messages queued in tx_buf */
|
||||
struct conf_order *running_config; /* Asynchronous config pointer */
|
||||
} cli;
|
||||
|
||||
extern pool *cli_pool;
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "conf/conf.h"
|
||||
#include "conf/parser.h"
|
||||
@ -106,9 +108,33 @@ sysdep_commit(struct config *new, struct config *old UNUSED)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 8
|
||||
#define UCO struct unix_conf_order *uco = (struct unix_conf_order *) co
|
||||
|
||||
struct unix_conf_order {
|
||||
struct conf_order co;
|
||||
struct unix_ifs *ifs;
|
||||
struct conf_order co; /* First field of struct conf_order is resource r; */
|
||||
struct unix_ifs *ifs; /* Input file stack; initially NULL, is inited inside config_parse() */
|
||||
struct linpool *ifs_lp; /* Where to allocate IFS from */
|
||||
struct cli *cli; /* CLI if called from CLI */
|
||||
event *ev; /* Start event if called from CLI */
|
||||
int type; /* Type of reconfig */
|
||||
uint timeout; /* Config timeout */
|
||||
};
|
||||
|
||||
static void
|
||||
unix_conf_order_free(resource *r)
|
||||
{
|
||||
struct unix_conf_order *uco = (struct unix_conf_order *) r;
|
||||
rfree(uco->ifs_lp);
|
||||
}
|
||||
|
||||
static struct resclass unix_conf_order_class = {
|
||||
"Unix Conf Order",
|
||||
sizeof(struct unix_conf_order),
|
||||
unix_conf_order_free,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct unix_ifs {
|
||||
@ -123,7 +149,7 @@ struct unix_ifs {
|
||||
static int
|
||||
unix_cf_read(struct conf_order *co, byte *dest, uint len)
|
||||
{
|
||||
struct unix_conf_order *uco = (struct unix_conf_order *) co;
|
||||
UCO;
|
||||
|
||||
ASSERT(uco->ifs->state == co->state);
|
||||
|
||||
@ -138,7 +164,7 @@ unix_cf_read(struct conf_order *co, byte *dest, uint len)
|
||||
cf_error(co->ctx, "Unable to open included file %s: %m", fn);
|
||||
}
|
||||
else
|
||||
cf_error(co->ctx, "Unable to open configuration file %s: %m", co->state->name);
|
||||
cf_error(co->ctx, "Unable to open: %m");
|
||||
|
||||
int l = read(uco->ifs->fd, dest, len);
|
||||
if (l < 0)
|
||||
@ -147,28 +173,26 @@ unix_cf_read(struct conf_order *co, byte *dest, uint len)
|
||||
}
|
||||
|
||||
static void
|
||||
unix_cf_include(struct conf_order *co, char *name, uint len)
|
||||
unix_cf_include(struct conf_order *co, const char *name, uint len)
|
||||
{
|
||||
struct unix_conf_order *uco = (struct unix_conf_order *) co;
|
||||
UCO;
|
||||
|
||||
if (!uco->ifs)
|
||||
cf_error(co->ctx, "Max include depth reached");
|
||||
|
||||
byte new_depth = uco->ifs->depth - 1;
|
||||
byte new_depth = uco->ifs ? (uco->ifs->depth - 1) : MAX_INCLUDE_DEPTH;
|
||||
|
||||
/* Includes are relative to the current file unless the path is absolute.
|
||||
* Joining the current file dirname with the include relative path. */
|
||||
char *patt;
|
||||
if (*name != '/')
|
||||
const char *patt;
|
||||
if (co->state && *name != '/')
|
||||
{
|
||||
/* dlen is upper bound of current file dirname length */
|
||||
int dlen = strlen(co->state->name);
|
||||
char *dir = alloca(dlen + 1);
|
||||
patt = alloca(dlen + len + 2);
|
||||
char *npatt = alloca(dlen + len + 2);
|
||||
|
||||
/* dirname() may overwrite its argument */
|
||||
memcpy(dir, co->state->name, dlen + 1);
|
||||
sprintf(patt, "%s/%s", dirname(dir), name);
|
||||
sprintf(npatt, "%s/%s", dirname(dir), name);
|
||||
patt = npatt;
|
||||
}
|
||||
else
|
||||
patt = name;
|
||||
@ -177,7 +201,7 @@ unix_cf_include(struct conf_order *co, char *name, uint len)
|
||||
response when the included config file is missing */
|
||||
if (!strpbrk(name, "?*["))
|
||||
{
|
||||
struct unix_ifs *uifs = cf_alloc(co->ctx, sizeof(struct unix_ifs));
|
||||
struct unix_ifs *uifs = lp_alloc(uco->ifs_lp, sizeof(struct unix_ifs));
|
||||
|
||||
*uifs = (struct unix_ifs) {
|
||||
.next = uco->ifs,
|
||||
@ -223,7 +247,7 @@ unix_cf_include(struct conf_order *co, char *name, uint len)
|
||||
continue;
|
||||
|
||||
/* Prepare new stack item */
|
||||
struct unix_ifs *uifs = cf_alloc(co->ctx, sizeof(struct unix_ifs));
|
||||
struct unix_ifs *uifs = lp_alloc(uco->ifs_lp, sizeof(struct unix_ifs));
|
||||
|
||||
*uifs = (struct unix_ifs) {
|
||||
.next = last_uifs,
|
||||
@ -247,7 +271,7 @@ unix_cf_include(struct conf_order *co, char *name, uint len)
|
||||
static int
|
||||
unix_cf_outclude(struct conf_order *co)
|
||||
{
|
||||
struct unix_conf_order *uco = (struct unix_conf_order *) co;
|
||||
UCO;
|
||||
|
||||
close(uco->ifs->fd);
|
||||
cf_free_state(co->ctx, uco->ifs->state);
|
||||
@ -261,112 +285,201 @@ unix_cf_outclude(struct conf_order *co)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 8
|
||||
typedef void (*cf_error_type)(struct conf_order *co, const char *msg, va_list args);
|
||||
typedef void (*cf_done_type)(struct conf_order *co);
|
||||
|
||||
typedef void (*cf_error_type)(struct conf_order *order, const char *msg, va_list args);
|
||||
|
||||
static struct config *
|
||||
unix_read_config(char *name, cf_error_type arg_cf_error)
|
||||
static struct unix_conf_order *
|
||||
unix_new_conf_order(pool *p)
|
||||
{
|
||||
struct conf_state state = { .name = name };
|
||||
struct unix_conf_order *uco = ralloc(p, &unix_conf_order_class);
|
||||
|
||||
uco->co.flags = CO_FILENAME;
|
||||
uco->co.cf_read_hook = unix_cf_read;
|
||||
uco->co.cf_include = unix_cf_include;
|
||||
uco->co.cf_outclude = unix_cf_outclude;
|
||||
|
||||
struct unix_ifs uifs = {
|
||||
.state = &state,
|
||||
.depth = MAX_INCLUDE_DEPTH,
|
||||
.fd = -1,
|
||||
};
|
||||
uco->ifs_lp = lp_new_default(p);
|
||||
|
||||
struct unix_conf_order uco = {
|
||||
.co = {
|
||||
.cf_read_hook = unix_cf_read,
|
||||
.cf_include = unix_cf_include,
|
||||
.cf_outclude = unix_cf_outclude,
|
||||
.cf_error = arg_cf_error,
|
||||
.state = &state,
|
||||
},
|
||||
.ifs = &uifs,
|
||||
};
|
||||
|
||||
if (config_parse(&uco.co))
|
||||
return uco.co.new_config;
|
||||
else
|
||||
return NULL;
|
||||
return uco;
|
||||
}
|
||||
|
||||
static void
|
||||
unix_cf_error_die(struct conf_order *order, const char *msg, va_list args)
|
||||
unix_cf_error_die(struct conf_order *co, const char *msg, va_list args)
|
||||
{
|
||||
die("%s, line %u: %V", order->state->name, order->state->lino, msg, &args);
|
||||
va_list cargs;
|
||||
va_copy(cargs, args);
|
||||
die("%s, line %u: %V", co->state->name, co->state->lino, msg, &cargs);
|
||||
va_end(cargs);
|
||||
}
|
||||
|
||||
struct config *
|
||||
read_config(void)
|
||||
{
|
||||
return unix_read_config(config_name, unix_cf_error_die);
|
||||
struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
|
||||
|
||||
uco->co.buf = config_name;
|
||||
uco->co.len = strlen(config_name);
|
||||
uco->co.flags |= CO_SYNC;
|
||||
uco->co.cf_error = unix_cf_error_die;
|
||||
|
||||
config_parse(&(uco->co));
|
||||
|
||||
struct config *c = uco->co.new_config;
|
||||
rfree(uco);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
unix_cf_error_log(struct conf_order *order, const char *msg, va_list args)
|
||||
unix_cf_error_log(struct conf_order *co, const char *msg, va_list args)
|
||||
{
|
||||
log(L_ERR "%s, line %u: %V", order->state->name, order->state->lino, msg, &args);
|
||||
va_list cargs;
|
||||
va_copy(cargs, args);
|
||||
log(L_ERR "%s, line %u: %V", co->state->name, co->state->lino, msg, &cargs);
|
||||
va_end(cargs);
|
||||
}
|
||||
|
||||
static void
|
||||
unix_cf_done_async(struct conf_order *co)
|
||||
{
|
||||
UCO;
|
||||
struct config *c = co->new_config;
|
||||
if (c)
|
||||
config_commit(c, RECONFIG_HARD, 0);
|
||||
|
||||
rfree(uco);
|
||||
}
|
||||
|
||||
void
|
||||
async_config(void)
|
||||
{
|
||||
log(L_INFO "Reconfiguration requested by SIGHUP");
|
||||
struct config *conf = unix_read_config(config_name, unix_cf_error_log);
|
||||
struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
|
||||
|
||||
if (conf)
|
||||
config_commit(conf, RECONFIG_HARD, 0);
|
||||
uco->co.buf = config_name;
|
||||
uco->co.len = strlen(config_name);
|
||||
uco->co.cf_error = unix_cf_error_log;
|
||||
uco->co.cf_done = unix_cf_done_async;
|
||||
|
||||
log(L_INFO "Reconfiguration requested by SIGHUP");
|
||||
config_parse(&(uco->co));
|
||||
}
|
||||
|
||||
static void
|
||||
unix_cf_error_cli(struct conf_order *order, const char *msg, va_list args)
|
||||
unix_cf_error_cli(struct conf_order *co, const char *msg, va_list args)
|
||||
{
|
||||
cli_msg(8002, "%s, line %d: %s", order->state->name, order->state->lino, msg, &args);
|
||||
cli_msg(8002, "%s, line %d: %s", co->state->name, co->state->lino, msg, &args);
|
||||
}
|
||||
|
||||
static struct config *
|
||||
cmd_read_config(char *name)
|
||||
{
|
||||
if (!name)
|
||||
name = config_name;
|
||||
static void cmd_reconfig_msg(cli *c, int r);
|
||||
|
||||
cli_msg(-2, "Reading configuration from %s", name);
|
||||
return unix_read_config(name, unix_cf_error_cli);
|
||||
/* Hack for scheduled undo notification */
|
||||
cli *cmd_reconfig_stored_cli;
|
||||
|
||||
static void
|
||||
unix_cf_done_cli(struct conf_order *co)
|
||||
{
|
||||
DBG("unix_cf_done_cli\n");
|
||||
UCO;
|
||||
cli_wakeup(uco->cli);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_done_config(struct unix_conf_order *uco)
|
||||
{
|
||||
DBG("config done handler\n");
|
||||
if (uco->type == RECONFIG_CHECK)
|
||||
{
|
||||
if (!uco->co.new_config)
|
||||
goto cleanup;
|
||||
|
||||
cli_printf(uco->cli, 20, "Configuration OK");
|
||||
config_free(uco->co.new_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct config *c = uco->co.new_config;
|
||||
if (!c)
|
||||
goto cleanup;
|
||||
|
||||
int r = config_commit(c, uco->type, uco->timeout);
|
||||
|
||||
if ((r >= 0) && (uco->timeout > 0))
|
||||
{
|
||||
cmd_reconfig_stored_cli = uco->cli;
|
||||
cli_printf(uco->cli, -22, "Undo scheduled in %d s", uco->timeout);
|
||||
}
|
||||
|
||||
cmd_reconfig_msg(uco->cli, r);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
DBG("config done handler: freeing the config order\n");
|
||||
rfree(uco);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_read_config_ev(void *data)
|
||||
{
|
||||
struct unix_conf_order *uco = data;
|
||||
log(L_INFO "Reading configuration from %s on CLI request: begin", uco->co.buf);
|
||||
return config_parse(&(uco->co));
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_read_config(struct unix_conf_order *uco)
|
||||
{
|
||||
DBG("cmd_read_config\n");
|
||||
uco->co.buf = uco->co.buf ?: config_name;
|
||||
uco->co.len = strlen(uco->co.buf);
|
||||
|
||||
uco->cli = this_cli;
|
||||
cli_msg(-2, "Reading configuration from %s", uco->co.buf);
|
||||
cli_write_trigger(uco->cli);
|
||||
|
||||
uco->co.cf_error = unix_cf_error_cli;
|
||||
uco->co.cf_done = unix_cf_done_cli;
|
||||
|
||||
uco->ev = ev_new(uco->co.pool);
|
||||
uco->ev->hook = cmd_read_config_ev;
|
||||
uco->ev->data = uco;
|
||||
|
||||
ev_schedule(uco->ev);
|
||||
|
||||
DBG("cmd_read_config: sleeping\n");
|
||||
cli_sleep(uco->cli);
|
||||
DBG("cmd_read_config: woken up\n");
|
||||
|
||||
cmd_done_config(uco);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_check_config(char *name)
|
||||
{
|
||||
struct config *conf = cmd_read_config(name);
|
||||
if (!conf)
|
||||
return;
|
||||
struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
|
||||
|
||||
cli_msg(20, "Configuration OK");
|
||||
config_free(conf);
|
||||
uco->co.buf = name;
|
||||
uco->type = RECONFIG_CHECK;
|
||||
|
||||
cmd_read_config(uco);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_reconfig_msg(int r)
|
||||
cmd_reconfig_msg(cli *c, int r)
|
||||
{
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
|
||||
case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
|
||||
case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
|
||||
case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
|
||||
case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
|
||||
case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
|
||||
case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
|
||||
case CONF_DONE: cli_printf(c, 3, "Reconfigured"); break;
|
||||
case CONF_PROGRESS: cli_printf(c, 4, "Reconfiguration in progress"); break;
|
||||
case CONF_QUEUED: cli_printf(c, 5, "Reconfiguration already in progress, queueing new config"); break;
|
||||
case CONF_UNQUEUED: cli_printf(c, 17, "Reconfiguration already in progress, removing queued config"); break;
|
||||
case CONF_CONFIRM: cli_printf(c, 18, "Reconfiguration confirmed"); break;
|
||||
case CONF_SHUTDOWN: cli_printf(c, 6, "Reconfiguration ignored, shutting down"); break;
|
||||
case CONF_NOTHING: cli_printf(c, 19, "Nothing to do"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hack for scheduled undo notification */
|
||||
cli *cmd_reconfig_stored_cli;
|
||||
|
||||
void
|
||||
cmd_reconfig_undo_notify(void)
|
||||
{
|
||||
@ -384,19 +497,13 @@ cmd_reconfig(char *name, int type, uint timeout)
|
||||
if (cli_access_restricted())
|
||||
return;
|
||||
|
||||
struct config *conf = cmd_read_config(name);
|
||||
if (!conf)
|
||||
return;
|
||||
struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
|
||||
|
||||
int r = config_commit(conf, type, timeout);
|
||||
uco->co.buf = name;
|
||||
uco->type = type;
|
||||
uco->timeout = timeout;
|
||||
|
||||
if ((r >= 0) && (timeout > 0))
|
||||
{
|
||||
cmd_reconfig_stored_cli = this_cli;
|
||||
cli_msg(-22, "Undo scheduled in %d s", timeout);
|
||||
}
|
||||
|
||||
cmd_reconfig_msg(r);
|
||||
return cmd_read_config(uco);
|
||||
}
|
||||
|
||||
void
|
||||
@ -406,7 +513,7 @@ cmd_reconfig_confirm(void)
|
||||
return;
|
||||
|
||||
int r = config_confirm();
|
||||
cmd_reconfig_msg(r);
|
||||
cmd_reconfig_msg(this_cli, r);
|
||||
}
|
||||
|
||||
void
|
||||
@ -418,6 +525,6 @@ cmd_reconfig_undo(void)
|
||||
cli_msg(-21, "Undo requested");
|
||||
|
||||
int r = config_undo();
|
||||
cmd_reconfig_msg(r);
|
||||
cmd_reconfig_msg(this_cli, r);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user