0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-21 22:07:03 +00:00

Conf: use coroutine to read new config

This commit is contained in:
Jan Maria Matejka 2018-08-30 16:45:45 +02:00
parent 642acc1b59
commit 4ec43aa137
10 changed files with 318 additions and 164 deletions

View File

@ -330,12 +330,6 @@ cf_hash(byte *c)
return h; 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 * struct conf_state *
cf_new_state(struct cf_context *ctx, const char *name) 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), .name = cfg_strdup(name),
.lino = 1, .lino = 1,
}; };
cf_init_state(ctx, cs); cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
return cs; return cs;
} }
@ -400,7 +394,7 @@ cf_init_kh(void)
* parsing of a new input. * parsing of a new input.
*/ */
struct cf_context * 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)); struct cf_context *ctx = order->ctx = lp_allocz(order->new_config->mem, sizeof(struct cf_context));
*ctx = (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)); cfx_lex_init_extra(ctx, &(ctx->yyscanner));
struct yyguts_t *yyg = ctx->yyscanner; struct yyguts_t *yyg = ctx->yyscanner;
cf_init_state(ctx, order->state); if (order->flags & CO_CLI)
yy_switch_to_buffer(order->state->buffer, yyg);
if (is_cli)
BEGIN(CLI); BEGIN(CLI);
else else
BEGIN(INITIAL); BEGIN(INITIAL);

View File

@ -103,16 +103,42 @@ config_alloc(struct pool *pp, struct linpool *lp)
return c; return c;
} }
int static void config_event_resume(void *arg)
config_parse(struct conf_order *order)
{ {
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) static void config_event_cleanup(void *arg)
order->new_config = config_alloc(order->pool, order->lp); {
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); rfree(ctx->coro);
int ret;
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)) if (setjmp(ctx->jmpbuf))
{ {
@ -120,58 +146,80 @@ config_parse(struct conf_order *order)
while (! order->cf_outclude(order)) while (! order->cf_outclude(order))
; ;
ret = 0;
config_free(ctx->new_config); config_free(ctx->new_config);
order->new_config = NULL; order->new_config = NULL;
goto cleanup; goto cleanup;
} }
sysdep_preconfig(ctx);
protos_preconfig(ctx->new_config);
rt_preconfig(ctx);
cfx_parse(ctx, ctx->yyscanner); 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"); cf_error(ctx, "No protocol is specified in the config file");
ret = 1;
cleanup: cleanup:
cf_free_context(ctx); if (order->flags & CO_SYNC)
order->ctx = NULL; return;
return ret;
DBG("config parse coroutine done, scheduling thread join\n");
coro_done(ctx->ev_cleanup);
bug("Resumed config when done.");
} }
int void
cli_parse(struct conf_order *order) config_parse(struct conf_order *order)
{ {
DBG("Parsing command line\n"); DBG("Parsing configuration\n");
struct config cc = {}; if (!order->new_config)
cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config"); order->new_config = config_alloc(order->pool, order->lp);
cc.mem = order->lp ?: lp_new_default(cc.pool);
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 (!(order->flags & CO_SYNC))
if (setjmp(ctx->jmpbuf)) {
goto done; ctx->ev_resume = ev_new(p);
ctx->ev_resume->hook = config_event_resume;
ctx->ev_resume->data = ctx;
cfx_parse(ctx, ctx->yyscanner); ctx->ev_cleanup = ev_new(p);
ok = 1; ctx->ev_cleanup->hook = config_event_cleanup;
ctx->ev_cleanup->data = ctx;
}
done: if (order->flags & CO_FILENAME)
cf_free_context(ctx); if (order->cf_include)
config_free(&cc); order->cf_include(order, order->buf, order->len);
order->new_config = NULL; else
order->ctx = NULL; bug("Include handler must be set to config from file");
return ok; 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 int
config_commit(struct config *c, int type, uint timeout) config_commit(struct config *c, int type, uint timeout)
{ {
ASSERT(type != RECONFIG_CHECK);
if (shutting_down) if (shutting_down)
{ {
config_free(c); config_free(c);

View File

@ -59,18 +59,30 @@ struct conf_state {
uint lino; /* Current line */ 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 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 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 pool *pool; /* If set, use this resource pool */
struct linpool *lp; /* If set, use this linpool */ struct linpool *lp; /* If set, use this linpool */
const char *buf; const char *buf; /* Buffer to parse or filename */
uint len; uint len; /* Buffer length */
enum conf_order_flag flags;
int (*cf_read_hook)(struct conf_order *order, byte *buf, uint max); 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); int (*cf_outclude)(struct conf_order *order);
void (*cf_error)(struct conf_order *order, const char *msg, va_list args); 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. */ /* 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: * Arguments:
* @order provides callbacks to read config files * @order provides callbacks to read config files
* *
* This function queues
* Return value: * Return value:
* 1 on success; order->new_config is then set to the parsed config * 1 on success; order->new_config is then set to the parsed config
* 0 on fail; order->new_config is undefined * 0 on fail; order->new_config is undefined
**/ **/
int config_parse(struct conf_order *order); void 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);
/** Callback for returning error from parser hooks */ /** Callback for returning error from parser hooks */
void cf_error(struct cf_context *, const char *msg, ...) NORET; void cf_error(struct cf_context *, const char *msg, ...) NORET;
@ -118,6 +117,7 @@ void order_shutdown(void);
#define RECONFIG_HARD 1 #define RECONFIG_HARD 1
#define RECONFIG_SOFT 2 #define RECONFIG_SOFT 2
#define RECONFIG_UNDO 3 #define RECONFIG_UNDO 3
#define RECONFIG_CHECK 4
#define CONF_DONE 0 #define CONF_DONE 0
#define CONF_PROGRESS 1 #define CONF_PROGRESS 1

View File

@ -22,6 +22,7 @@ CF_HDR
#include "nest/route.h" #include "nest/route.h"
#include "nest/cli.h" #include "nest/cli.h"
#include "filter/filter.h" #include "filter/filter.h"
#include "lib/coroutine.h"
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */ /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
@ -33,6 +34,9 @@ struct config *new_config;
jmp_buf jmpbuf; jmp_buf jmpbuf;
linpool *cfg_mem; linpool *cfg_mem;
struct conf_order *order; struct conf_order *order;
coroutine *coro;
event *ev_resume;
event *ev_cleanup;
CF_DEFINES CF_DEFINES

View File

@ -27,7 +27,7 @@ union YYSTYPE;
int cfx_lex(union YYSTYPE *, yyscan_t); int cfx_lex(union YYSTYPE *, yyscan_t);
/* Config context alloc and free */ /* 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 *); void cf_free_context(struct cf_context *);
/* Lexer state alloc and free */ /* Lexer state alloc and free */

View File

@ -33,6 +33,7 @@ Reply codes of BIRD command-line interface
0022 Undo scheduled 0022 Undo scheduled
0023 Evaluation of expression 0023 Evaluation of expression
0024 Graceful restart status report 0024 Graceful restart status report
0025 Reconfiguration rejected, another config not parsed yet
1000 BIRD version 1000 BIRD version
1001 Interface list 1001 Interface list

View File

@ -11,6 +11,8 @@
#include "lib/lists.h" #include "lib/lists.h"
#include <stdlib.h>
/* Resource */ /* Resource */
typedef struct resource { typedef struct resource {

View File

@ -442,6 +442,7 @@ cli_command(struct cli *c)
.cf_error = cli_cmd_error, .cf_error = cli_cmd_error,
.lp = c->parser_pool, .lp = c->parser_pool,
.pool = c->pool, .pool = c->pool,
.flags = CO_CLI | CO_SYNC,
}, },
.cli = c, .cli = c,
}; };
@ -451,7 +452,7 @@ cli_command(struct cli *c)
lp_flush(c->parser_pool); lp_flush(c->parser_pool);
this_cli = c; 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) c->async_msg_size < CLI_MAX_ASYNC_QUEUE)
cli_copy_message(c); cli_copy_message(c);
cli_write_trigger(c);
if (c->state == CLI_STATE_YIELD || if (c->state == CLI_STATE_YIELD ||
c->state == CLI_STATE_WAIT_TX && !c->tx_pos) c->state == CLI_STATE_WAIT_TX && !c->tx_pos)
coro_resume(c->coro); coro_resume(c->coro);

View File

@ -66,6 +66,7 @@ typedef struct cli {
uint log_mask; /* Mask of allowed message levels */ uint log_mask; /* Mask of allowed message levels */
uint log_threshold; /* When free < log_threshold, store only important messages */ uint log_threshold; /* When free < log_threshold, store only important messages */
uint async_msg_size; /* Total size of async messages queued in tx_buf */ uint async_msg_size; /* Total size of async messages queued in tx_buf */
struct conf_order *running_config; /* Asynchronous config pointer */
} cli; } cli;
extern pool *cli_pool; extern pool *cli_pool;

View File

@ -16,6 +16,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#undef LOCAL_DEBUG
#include "nest/bird.h" #include "nest/bird.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "conf/parser.h" #include "conf/parser.h"
@ -106,9 +108,33 @@ sysdep_commit(struct config *new, struct config *old UNUSED)
return 0; return 0;
} }
#define MAX_INCLUDE_DEPTH 8
#define UCO struct unix_conf_order *uco = (struct unix_conf_order *) co
struct unix_conf_order { struct unix_conf_order {
struct conf_order co; struct conf_order co; /* First field of struct conf_order is resource r; */
struct unix_ifs *ifs; 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 { struct unix_ifs {
@ -123,7 +149,7 @@ struct unix_ifs {
static int static int
unix_cf_read(struct conf_order *co, byte *dest, uint len) 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); 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); cf_error(co->ctx, "Unable to open included file %s: %m", fn);
} }
else 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); int l = read(uco->ifs->fd, dest, len);
if (l < 0) if (l < 0)
@ -147,28 +173,26 @@ unix_cf_read(struct conf_order *co, byte *dest, uint len)
} }
static void 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) byte new_depth = uco->ifs ? (uco->ifs->depth - 1) : MAX_INCLUDE_DEPTH;
cf_error(co->ctx, "Max include depth reached");
byte new_depth = uco->ifs->depth - 1;
/* Includes are relative to the current file unless the path is absolute. /* Includes are relative to the current file unless the path is absolute.
* Joining the current file dirname with the include relative path. */ * Joining the current file dirname with the include relative path. */
char *patt; const char *patt;
if (*name != '/') if (co->state && *name != '/')
{ {
/* dlen is upper bound of current file dirname length */ /* dlen is upper bound of current file dirname length */
int dlen = strlen(co->state->name); int dlen = strlen(co->state->name);
char *dir = alloca(dlen + 1); char *dir = alloca(dlen + 1);
patt = alloca(dlen + len + 2); char *npatt = alloca(dlen + len + 2);
/* dirname() may overwrite its argument */ /* dirname() may overwrite its argument */
memcpy(dir, co->state->name, dlen + 1); memcpy(dir, co->state->name, dlen + 1);
sprintf(patt, "%s/%s", dirname(dir), name); sprintf(npatt, "%s/%s", dirname(dir), name);
patt = npatt;
} }
else else
patt = name; 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 */ response when the included config file is missing */
if (!strpbrk(name, "?*[")) 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) { *uifs = (struct unix_ifs) {
.next = uco->ifs, .next = uco->ifs,
@ -223,7 +247,7 @@ unix_cf_include(struct conf_order *co, char *name, uint len)
continue; continue;
/* Prepare new stack item */ /* 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) { *uifs = (struct unix_ifs) {
.next = last_uifs, .next = last_uifs,
@ -247,7 +271,7 @@ unix_cf_include(struct conf_order *co, char *name, uint len)
static int static int
unix_cf_outclude(struct conf_order *co) unix_cf_outclude(struct conf_order *co)
{ {
struct unix_conf_order *uco = (struct unix_conf_order *) co; UCO;
close(uco->ifs->fd); close(uco->ifs->fd);
cf_free_state(co->ctx, uco->ifs->state); cf_free_state(co->ctx, uco->ifs->state);
@ -261,112 +285,201 @@ unix_cf_outclude(struct conf_order *co)
return 0; 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 unix_conf_order *
unix_new_conf_order(pool *p)
static struct config *
unix_read_config(char *name, cf_error_type arg_cf_error)
{ {
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 = { uco->ifs_lp = lp_new_default(p);
.state = &state,
.depth = MAX_INCLUDE_DEPTH,
.fd = -1,
};
struct unix_conf_order uco = { return 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;
} }
static void 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 * struct config *
read_config(void) 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 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 void
async_config(void) async_config(void)
{ {
log(L_INFO "Reconfiguration requested by SIGHUP"); struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
struct config *conf = unix_read_config(config_name, unix_cf_error_log);
if (conf) uco->co.buf = config_name;
config_commit(conf, RECONFIG_HARD, 0); 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 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 * static void cmd_reconfig_msg(cli *c, int r);
cmd_read_config(char *name)
{
if (!name)
name = config_name;
cli_msg(-2, "Reading configuration from %s", name); /* Hack for scheduled undo notification */
return unix_read_config(name, unix_cf_error_cli); 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 void
cmd_check_config(char *name) cmd_check_config(char *name)
{ {
struct config *conf = cmd_read_config(name); struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
if (!conf)
return;
cli_msg(20, "Configuration OK"); uco->co.buf = name;
config_free(conf); uco->type = RECONFIG_CHECK;
cmd_read_config(uco);
} }
static void static void
cmd_reconfig_msg(int r) cmd_reconfig_msg(cli *c, int r)
{ {
switch (r) switch (r)
{ {
case CONF_DONE: cli_msg( 3, "Reconfigured"); break; case CONF_DONE: cli_printf(c, 3, "Reconfigured"); break;
case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break; case CONF_PROGRESS: cli_printf(c, 4, "Reconfiguration in progress"); break;
case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break; case CONF_QUEUED: cli_printf(c, 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_UNQUEUED: cli_printf(c, 17, "Reconfiguration already in progress, removing queued config"); break;
case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break; case CONF_CONFIRM: cli_printf(c, 18, "Reconfiguration confirmed"); break;
case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break; case CONF_SHUTDOWN: cli_printf(c, 6, "Reconfiguration ignored, shutting down"); break;
case CONF_NOTHING: cli_msg(19, "Nothing to do"); break; case CONF_NOTHING: cli_printf(c, 19, "Nothing to do"); break;
default: break; default: break;
} }
} }
/* Hack for scheduled undo notification */
cli *cmd_reconfig_stored_cli;
void void
cmd_reconfig_undo_notify(void) cmd_reconfig_undo_notify(void)
{ {
@ -384,19 +497,13 @@ cmd_reconfig(char *name, int type, uint timeout)
if (cli_access_restricted()) if (cli_access_restricted())
return; return;
struct config *conf = cmd_read_config(name); struct unix_conf_order *uco = unix_new_conf_order(&root_pool);
if (!conf)
return;
int r = config_commit(conf, type, timeout); uco->co.buf = name;
uco->type = type;
uco->timeout = timeout;
if ((r >= 0) && (timeout > 0)) return cmd_read_config(uco);
{
cmd_reconfig_stored_cli = this_cli;
cli_msg(-22, "Undo scheduled in %d s", timeout);
}
cmd_reconfig_msg(r);
} }
void void
@ -406,7 +513,7 @@ cmd_reconfig_confirm(void)
return; return;
int r = config_confirm(); int r = config_confirm();
cmd_reconfig_msg(r); cmd_reconfig_msg(this_cli, r);
} }
void void
@ -418,6 +525,6 @@ cmd_reconfig_undo(void)
cli_msg(-21, "Undo requested"); cli_msg(-21, "Undo requested");
int r = config_undo(); int r = config_undo();
cmd_reconfig_msg(r); cmd_reconfig_msg(this_cli, r);
} }