From: Jan Maria Matejka Date: Thu, 30 Aug 2018 14:45:45 +0000 (+0200) Subject: Conf: use coroutine to read new config X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4ec43aa137923320ab23bd9e549e08b94dc4d189;p=thirdparty%2Fbird.git Conf: use coroutine to read new config --- diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 32dc576a6..895e5afaa 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -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); diff --git a/conf/conf.c b/conf/conf.c index 1048296cf..99d98c280 100644 --- a/conf/conf.c +++ b/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; + + rfree(ctx->coro); + + cf_free_context(ctx); + order->ctx = NULL; + + if (order->flags & CO_CLI) + { + config_free(order->new_config); + order->new_config = NULL; + } - struct cf_context *ctx = cf_new_context(0, order); - int ret; + 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); diff --git a/conf/conf.h b/conf/conf.h index 999e09963..038ef0e77 100644 --- a/conf/conf.h +++ b/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 diff --git a/conf/confbase.Y b/conf/confbase.Y index d9bcbad56..bad8b0a10 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -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 diff --git a/conf/parser.h b/conf/parser.h index 1d858cf16..112632cab 100644 --- a/conf/parser.h +++ b/conf/parser.h @@ -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 */ diff --git a/doc/reply_codes b/doc/reply_codes index 3a7f2c907..04b000c88 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -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 diff --git a/lib/resource.h b/lib/resource.h index d9d4bb8f1..1455c474b 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -11,6 +11,8 @@ #include "lib/lists.h" +#include + /* Resource */ typedef struct resource { diff --git a/nest/cli.c b/nest/cli.c index aa69e71e2..2fefb08a7 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -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); diff --git a/nest/cli.h b/nest/cli.h index 80aea3755..c0470a233 100644 --- a/nest/cli.h +++ b/nest/cli.h @@ -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; diff --git a/sysdep/unix/conf.c b/sysdep/unix/conf.c index 571909b26..785044734 100644 --- a/sysdep/unix/conf.c +++ b/sysdep/unix/conf.c @@ -16,6 +16,8 @@ #include #include +#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 *order, const char *msg, va_list args); +typedef void (*cf_error_type)(struct conf_order *co, const char *msg, va_list args); +typedef void (*cf_done_type)(struct conf_order *co); -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_ifs uifs = { - .state = &state, - .depth = MAX_INCLUDE_DEPTH, - .fd = -1, - }; - - 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; + 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; + + uco->ifs_lp = lp_new_default(p); + + 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) { + struct unix_conf_order *uco = unix_new_conf_order(&root_pool); + + 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"); - struct config *conf = unix_read_config(config_name, unix_cf_error_log); + config_parse(&(uco->co)); +} - if (conf) - config_commit(conf, RECONFIG_HARD, 0); +static void +unix_cf_error_cli(struct conf_order *co, const char *msg, va_list args) +{ + cli_msg(8002, "%s, line %d: %s", co->state->name, co->state->lino, msg, &args); } +static void cmd_reconfig_msg(cli *c, int r); + +/* Hack for scheduled undo notification */ +cli *cmd_reconfig_stored_cli; + static void -unix_cf_error_cli(struct conf_order *order, const char *msg, va_list args) +unix_cf_done_cli(struct conf_order *co) { - cli_msg(8002, "%s, line %d: %s", order->state->name, order->state->lino, msg, &args); + DBG("unix_cf_done_cli\n"); + UCO; + cli_wakeup(uco->cli); } -static struct config * -cmd_read_config(char *name) +static void +cmd_done_config(struct unix_conf_order *uco) { - if (!name) - name = config_name; + 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; - cli_msg(-2, "Reading configuration from %s", name); - return unix_read_config(name, unix_cf_error_cli); + 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); + + uco->co.buf = name; + uco->type = RECONFIG_CHECK; - cli_msg(20, "Configuration OK"); - config_free(conf); + 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; - - int r = config_commit(conf, type, timeout); + struct unix_conf_order *uco = unix_new_conf_order(&root_pool); - if ((r >= 0) && (timeout > 0)) - { - cmd_reconfig_stored_cli = this_cli; - cli_msg(-22, "Undo scheduled in %d s", timeout); - } + uco->co.buf = name; + uco->type = type; + uco->timeout = 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); }