From de81823f3e5e49d6e54922d5781a8b70b63416ea Mon Sep 17 00:00:00 2001 From: Krisztian Litkey Date: Fri, 9 Nov 2012 19:25:10 +0200 Subject: [PATCH] console: best-effort std{out,err} redirection during console commands. --- src/core/console-command.c | 8 +- src/core/console.c | 88 +++++++++++++++++++++- src/core/lua-bindings/lua-console.c | 20 ++--- src/plugins/domain-control/plugin-domain-control.c | 3 +- src/plugins/plugin-test.c | 62 +++++++-------- .../resource-native/plugin-resource-native.c | 17 +++-- 6 files changed, 141 insertions(+), 57 deletions(-) diff --git a/src/core/console-command.c b/src/core/console-command.c index 1d58ea2..7bfa496 100644 --- a/src/core/console-command.c +++ b/src/core/console-command.c @@ -265,26 +265,28 @@ MRP_CONSOLE_GROUP(builtin_cmd_group, "", NULL, NULL, { static void debug_enable(mrp_console_t *c, void *user_data, int argc, char **argv) { + MRP_UNUSED(c); MRP_UNUSED(argc); MRP_UNUSED(argv); MRP_UNUSED(user_data); mrp_debug_enable(TRUE); - mrp_console_printf(c, "Debugging is now enabled.\n"); + printf("Debugging is now enabled.\n"); } static void debug_disable(mrp_console_t *c, void *user_data, int argc, char **argv) { + MRP_UNUSED(c); MRP_UNUSED(argc); MRP_UNUSED(argv); MRP_UNUSED(user_data); mrp_debug_enable(FALSE); - mrp_console_printf(c, "Debugging is now disabled.\n"); + printf("Debugging is now disabled.\n"); } @@ -335,7 +337,7 @@ static void debug_reset(mrp_console_t *c, void *user_data, mrp_debug_reset(); - mrp_console_printf(c, "Debugging configuration has been reset to default."); + printf("Debugging configuration has been reset to default."); } diff --git a/src/core/console.c b/src/core/console.c index 170ad83..21bd29f 100644 --- a/src/core/console.c +++ b/src/core/console.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,10 @@ #define CWARN COLOR""YELLOW #define CERR COLOR""RED +#define RFD 0 +#define WFD 1 + + #define MRP_CFG_MAXLINE 4096 /* input line length limit */ #define MRP_CFG_MAXARGS 64 /* command argument limit */ @@ -86,20 +91,24 @@ typedef struct { char prompt[MAX_PROMPT]; /* current prompt */ input_t in; /* input buffer */ mrp_list_hook_t hook; /* to list of active consoles */ + int pout[2]; /* pipe for output proxying */ + int ofd; /* saved fileno(stdout) */ + int oblk; /* saved O_NONBLOCK for ofd */ + int efd; /* saved fileno(stderr) */ + int eblk; /* saved O_NONBLOCK for efd */ } console_t; static int check_destroy(mrp_console_t *mc); static int purge_destroyed(mrp_console_t *mc); static FILE *console_fopen(mrp_console_t *mc); +static void console_release_output(console_t *c); static ssize_t input_evt(mrp_console_t *mc, void *buf, size_t size); static void disconnected_evt(mrp_console_t *c, int error); static ssize_t complete_evt(mrp_console_t *c, void *input, size_t isize, char **completions, size_t csize); - - static void register_commands(mrp_context_t *ctx); static void unregister_commands(mrp_context_t *ctx); @@ -162,6 +171,9 @@ mrp_console_t *mrp_create_console(mrp_context_t *ctx, mrp_console_req_t *req, c->in.line = 0; c->in.fd = -1; + pipe(c->pout); + c->ofd = c->efd = -1; + mrp_list_append(&ctx->consoles, &c->hook); mrp_set_console_prompt((mrp_console_t *)c); } @@ -193,6 +205,10 @@ static int purge_destroyed(mrp_console_t *mc) fclose(c->stdout); fclose(c->stderr); + console_release_output(c); + close(c->pout[0]); + close(c->pout[1]); + c->req.free(c->backend_data); mrp_free(c); @@ -358,6 +374,54 @@ int mrp_console_del_core_group(mrp_console_group_t *group) } +static void console_grab_output(console_t *c) +{ + int ofd = fileno(stdout); + int efd = fileno(stderr); + int blk; + + if (c->ofd == -1 && c->pout[RFD] != -1) { + blk = fcntl(ofd, F_GETFL, 0); + c->oblk = (blk > 0 && (blk & O_NONBLOCK)); + blk = fcntl(efd, F_GETFL, 0); + c->eblk = (blk > 0 && (blk & O_NONBLOCK)); + + c->ofd = dup(ofd); + dup2(c->pout[WFD], ofd); + fcntl(c->pout[RFD], F_SETFL, O_NONBLOCK); + + c->efd = dup(efd); + dup2(c->pout[WFD], efd); + fcntl(c->pout[WFD], F_SETFL, O_NONBLOCK); + } +} + + +static void console_release_output(console_t *c) +{ + int ofd = fileno(stdout); + int efd = fileno(stderr); + + if (c->ofd >= 0) { + dup2(c->ofd, ofd); + c->ofd = -1; + fcntl(ofd, F_SETFL, c->oblk); + } + + if (c->efd >= 0) { + dup2(c->efd, efd); + c->efd = -1; + fcntl(efd, F_SETFL, c->eblk); + } +} + + +static int console_read_output(console_t *c, void *buf, size_t size) +{ + return read(c->pout[RFD], buf, size); +} + + static ssize_t input_evt(mrp_console_t *mc, void *buf, size_t size) { console_t *c = (console_t *)mc; @@ -480,9 +544,29 @@ static ssize_t input_evt(mrp_console_t *mc, void *buf, size_t size) execute: if (cmd != NULL) { + console_grab_output(c); + + clearerr(stdout); + clearerr(stderr); + MRP_CONSOLE_BUSY(mc, { cmd->tok(mc, grp->user_data, argc, argv); }); + + { + char data[1024]; + int size; + + while ((size = console_read_output(c, data, sizeof(data))) > 0) { + dprintf(c->ofd, "%*.*s", size, size, data); + mrp_console_printf(mc, "%*.*s", size, size, data); + } + + if (ferror(stdout) || ferror(stderr)) + mrp_console_printf(mc, "[console output truncated...]\n"); + } + + console_release_output(c); } else { unknown_command: diff --git a/src/core/lua-bindings/lua-console.c b/src/core/lua-bindings/lua-console.c index ec0babe..f224ebd 100644 --- a/src/core/lua-bindings/lua-console.c +++ b/src/core/lua-bindings/lua-console.c @@ -15,12 +15,13 @@ static void eval_cb(mrp_console_t *c, void *user_data, int argc, char **argv) char code[1024], *p; int i, n, l, len; + MRP_UNUSED(c); MRP_UNUSED(user_data); L = mrp_lua_get_lua_state(); if (L == NULL) { - mrp_console_printf(c, "Lua runtime not available or initialized."); + printf("Lua runtime not available or initialized."); return; } @@ -39,7 +40,7 @@ static void eval_cb(mrp_console_t *c, void *user_data, int argc, char **argv) } if (luaL_loadbuffer(L, code, len, "") || lua_pcall(L, 0, 0, 0)) - mrp_console_printf(c, "Lua error: %s\n", lua_tostring(L, -1)); + printf("Lua error: %s\n", lua_tostring(L, -1)); lua_settop(L, 0); } @@ -54,10 +55,11 @@ static void source_cb(mrp_console_t *c, void *user_data, int argc, char **argv) ssize_t len; int fd; + MRP_UNUSED(c); MRP_UNUSED(user_data); if (argc != 3) { - mrp_console_printf(c, "Invalid arguments, expecting a single path."); + printf("Invalid arguments, expecting a single path."); return; } else @@ -66,7 +68,7 @@ static void source_cb(mrp_console_t *c, void *user_data, int argc, char **argv) L = mrp_lua_get_lua_state(); if (L == NULL) { - mrp_console_printf(c, "Lua runtime not available or initialized."); + printf("Lua runtime not available or initialized."); return; } @@ -83,19 +85,17 @@ static void source_cb(mrp_console_t *c, void *user_data, int argc, char **argv) if (len > 0) { if (luaL_loadbuffer(L, code, len, path) != 0 || lua_pcall(L, 0, 0, 0) != 0) - mrp_console_printf(c, "Lua error: %s\n", - lua_tostring(L, -1)); + printf("Lua error: %s\n", lua_tostring(L, -1)); lua_settop(L, 0); } } else - mrp_console_printf(c, "Failed to open %s (%d: %s).", path, - errno, strerror(errno)); + printf("Failed to open %s (%d: %s).", path, + errno, strerror(errno)); } else - mrp_console_printf(c, "Failed to open %s (%d: %s).", path, - errno, strerror(errno)); + printf("Failed to open %s (%d: %s).", path, errno, strerror(errno)); } } diff --git a/src/plugins/domain-control/plugin-domain-control.c b/src/plugins/domain-control/plugin-domain-control.c index 934edc6..c0c240e 100644 --- a/src/plugins/domain-control/plugin-domain-control.c +++ b/src/plugins/domain-control/plugin-domain-control.c @@ -28,11 +28,12 @@ static void plugin_exit(mrp_plugin_t *plugin) static void cmd_cb(mrp_console_t *c, void *user_data, int argc, char **argv) { + MRP_UNUSED(c); MRP_UNUSED(user_data); MRP_UNUSED(argc); MRP_UNUSED(argv); - mrp_console_printf(c, "domctrl:%s() called...\n", __FUNCTION__); + printf("domctrl:%s() called...\n", __FUNCTION__); } diff --git a/src/plugins/plugin-test.c b/src/plugins/plugin-test.c index 8ced359..3e37f5b 100644 --- a/src/plugins/plugin-test.c +++ b/src/plugins/plugin-test.c @@ -126,7 +126,6 @@ void one_cb(mrp_console_t *c, void *user_data, int argc, char **argv) for (i = 0; i < argc; i++) { printf("%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); - mrp_console_printf(c, "%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); } } @@ -139,7 +138,6 @@ void two_cb(mrp_console_t *c, void *user_data, int argc, char **argv) for (i = 0; i < argc; i++) { printf("%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); - mrp_console_printf(c, "%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); } } @@ -152,7 +150,6 @@ void three_cb(mrp_console_t *c, void *user_data, int argc, char **argv) for (i = 0; i < argc; i++) { printf("%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); - mrp_console_printf(c, "%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); } } @@ -165,7 +162,6 @@ void four_cb(mrp_console_t *c, void *user_data, int argc, char **argv) for (i = 0; i < argc; i++) { printf("%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); - mrp_console_printf(c, "%s(): #%d: '%s'\n", __FUNCTION__, i, argv[i]); } } @@ -181,10 +177,9 @@ void db_script_cb(mrp_console_t *c, void *user_data, int argc, char **argv) for (i = 2; i < argc; i++) { tx = mqi_begin_transaction(); if (mql_exec_file(argv[i]) < 0) - mrp_console_printf(c, "failed to execute DB script: %s\n", - strerror(errno)); + printf("failed to execute DB script: %s\n", strerror(errno)); else - mrp_console_printf(c, "DB script executed OK\n"); + printf("DB script executed OK\n"); mqi_commit_transaction(tx); } } @@ -208,21 +203,20 @@ void db_cmd_cb(mrp_console_t *c, void *user_data, int argc, char **argv) n -= l; if ((tx = mqi_begin_transaction()) == MQI_HANDLE_INVALID) - mrp_console_printf(c, "failed to create DB transaction\n"); + printf("failed to create DB transaction\n"); r = mql_exec_string(mql_result_string, buf); if (!mql_result_is_success(r)) { - mrp_console_printf(c, "failed to execute DB command '%s'\n", - buf); + printf("failed to execute DB command '%s'\n", buf); } else { - mrp_console_printf(c, "DB command executed OK\n"); - mrp_console_printf(c, "%s\n", mql_result_string_get(r)); + printf("DB command executed OK\n"); + printf("%s\n", mql_result_string_get(r)); } mql_result_free(r); if (mqi_commit_transaction(tx) < 0) - mrp_console_printf(c, "failed to commit DB transaction\n"); + printf("failed to commit DB transaction\n"); } } @@ -239,15 +233,15 @@ void resolve_cb(mrp_console_t *c, void *user_data, int argc, char **argv) if (ctx->r != NULL) { if (mrp_resolver_update_target(ctx->r, target, NULL) > 0) - mrp_console_printf(c, "'%s' updated OK.\n", target); + printf("'%s' updated OK.\n", target); else - mrp_console_printf(c, "Failed to update '%s'.\n", target); + printf("Failed to update '%s'.\n", target); } else - mrp_console_printf(c, "Resolver/ruleset is not available.\n"); + printf("Resolver/ruleset is not available.\n"); } else { - mrp_console_printf(c, "Usage: %s %s \n", argv[0], argv[1]); + printf("Usage: %s %s \n", argv[0], argv[1]); } } @@ -507,7 +501,7 @@ static void success_cb(uint32_t tx, void *data) { mrp_console_t *c = data; - mrp_console_printf(c, "%s(): transaction %u\n", __FUNCTION__, tx); + printf("%s(): transaction %u\n", __FUNCTION__, tx); } @@ -515,8 +509,8 @@ static void error_cb(uint32_t tx, mrp_tx_error_t err, void *data) { mrp_console_t *c = data; - mrp_console_printf(c, "%s(): transaction %u error: %s\n", __FUNCTION__, - tx, (err == MRP_TX_ERROR_NACKED) ? "NACK" : "no reply"); + printf("%s(): transaction %u error: %s\n", __FUNCTION__, + tx, (err == MRP_TX_ERROR_NACKED) ? "NACK" : "no reply"); } @@ -587,15 +581,15 @@ void signalling_cb_3(mrp_console_t *c, void *user_data, int argc, char **argv) ret = mrp_tx_close_signal(tx); - mrp_console_printf(c, "%s(): tried to send a cancelled transction %u -- success %i\n", - __FUNCTION__, tx, ret); + printf("%s(): tried to send a cancelled transction %u -- success %i\n", + __FUNCTION__, tx, ret); } static void info_cb(char *msg, void *data) { mrp_console_t *c = data; - mrp_console_printf(c, "received msg '%s'\n", msg); + printf("received msg '%s'\n", msg); } void signalling_info_register_cb(mrp_console_t *c, void *user_data, @@ -615,9 +609,9 @@ void signalling_info_register_cb(mrp_console_t *c, void *user_data, ret = mrp_info_register(ep, info_cb, c); if (ret < 0) - mrp_console_printf(c, "Failed to register back channel to EP '%s'\n", ep); + printf("Failed to register back channel to EP '%s'\n", ep); else - mrp_console_printf(c, "Registered back channel to EP '%s'\n", ep); + printf("Registered back channel to EP '%s'\n", ep); } @@ -635,7 +629,7 @@ void signalling_info_unregister_cb(mrp_console_t *c, void *user_data, mrp_info_unregister(ep); - mrp_console_printf(c, "Unregistered back channel to EP '%s'\n", ep); + printf("Unregistered back channel to EP '%s'\n", ep); } @@ -643,11 +637,11 @@ static void dump_decision(mrp_console_t *c, ep_decision_t *msg) { uint i; - mrp_console_printf(c, "Message contents:\n"); + printf("Message contents:\n"); for (i = 0; i < msg->n_rows; i++) { - mrp_console_printf(c, "row %d: '%s'\n", i+1, msg->rows[i]); + printf("row %d: '%s'\n", i+1, msg->rows[i]); } - mrp_console_printf(c, "%s required.\n\n", + printf("%s required.\n\n", msg->reply_required ? "Reply" : "No reply"); } @@ -660,7 +654,7 @@ static void recvfrom_evt(mrp_transport_t *t, void *data, uint16_t tag, MRP_UNUSED(addr); MRP_UNUSED(addrlen); - mrp_console_printf(c, "Received message (0x%02x)\n", tag); + printf("Received message (0x%02x)\n", tag); switch (tag) { case TAG_POLICY_DECISION: @@ -703,7 +697,7 @@ static void closed_evt(mrp_transport_t *t, int error, void *user_data) MRP_UNUSED(t); MRP_UNUSED(error); - mrp_console_printf(c, "Received closed event\n"); + printf("Received closed event\n"); } @@ -736,13 +730,13 @@ void signalling_create_ep_cb(mrp_console_t *c, void *user_data, alen = mrp_transport_resolve(NULL, "internal:signalling", &addr, sizeof(addr), NULL); if (alen <= 0) { - mrp_console_printf(c, "Error: resolving address failed!\n"); + printf("Error: resolving address failed!\n"); return; } ret = mrp_transport_connect(t, &addr, alen); if (ret == 0) { - mrp_console_printf(c, "Error: connect failed!\n"); + printf("Error: connect failed!\n"); return; } @@ -753,7 +747,7 @@ void signalling_create_ep_cb(mrp_console_t *c, void *user_data, ret = mrp_transport_senddata(t, &msg, TAG_REGISTER); if (!ret) { - mrp_console_printf(c, "Failed to send register message\n"); + printf("Failed to send register message\n"); return; } } diff --git a/src/plugins/resource-native/plugin-resource-native.c b/src/plugins/resource-native/plugin-resource-native.c index f8b24b2..2ac4404 100644 --- a/src/plugins/resource-native/plugin-resource-native.c +++ b/src/plugins/resource-native/plugin-resource-native.c @@ -128,16 +128,17 @@ static void print_zones_cb(mrp_console_t *c, void *user_data, const char **zone_names; int i; + MRP_UNUSED(c); MRP_UNUSED(user_data); MRP_UNUSED(argc); MRP_UNUSED(argv); - mrp_console_printf(c, "Zones:\n"); + printf("Zones:\n"); if ((zone_names = mrp_zone_get_all_names(0, NULL))) { for (i = 0; zone_names[i]; i++) - mrp_console_printf (c, " %s\n", zone_names[i]); + printf(" %s\n", zone_names[i]); mrp_free(zone_names); @@ -151,17 +152,17 @@ static void print_classes_cb(mrp_console_t *c, void *user_data, const char **class_names; int i; + MRP_UNUSED(c); MRP_UNUSED(user_data); MRP_UNUSED(argc); MRP_UNUSED(argv); - mrp_console_printf(c, "Application classes:\n"); + printf("Application classes:\n"); if ((class_names = mrp_application_class_get_all_names(0, NULL))) { for (i = 0; class_names[i]; i++) - mrp_console_printf(c, " %s\n", class_names[i]); - + printf(" %s\n", class_names[i]); mrp_free(class_names); } @@ -173,13 +174,14 @@ static void print_sets_cb(mrp_console_t *c, void *user_data, { char buf[8192]; + MRP_UNUSED(c); MRP_UNUSED(user_data); MRP_UNUSED(argc); MRP_UNUSED(argv); mrp_application_class_print(buf, sizeof(buf)); - mrp_console_printf(c, "%s", buf); + printf("%s", buf); } @@ -188,13 +190,14 @@ static void print_owners_cb(mrp_console_t *c, void *user_data, { char buf[2048]; + MRP_UNUSED(c); MRP_UNUSED(user_data); MRP_UNUSED(argc); MRP_UNUSED(argv); mrp_resource_owner_print(buf, sizeof(buf)); - mrp_console_printf(c, "%s", buf); + printf("%s", buf); } static int set_default_configuration(void) -- 2.7.4