diff --git a/cli/cli.c b/cli/cli.c index c14653f373..108c776265 100644 --- a/cli/cli.c +++ b/cli/cli.c @@ -10,9 +10,6 @@ static uv_shutdown_t shutdown_req; static char command_string[MAX_COMMAND_LENGTH]; static unsigned command_string_size; -static char response_string[MAX_COMMAND_LENGTH]; -static unsigned response_string_size; - static int exit_status; struct command_context { @@ -24,8 +21,10 @@ struct command_context { cmd_status_t status; }; -static void parse_command_reply(void) +static void parse_command_reply(BUFFER *buf) { + char *response_string = (char *) buffer_tostring(buf); + unsigned response_string_size = buffer_strlen(buf); FILE *stream = NULL; char *pos; int syntax_error = 0; @@ -64,28 +63,21 @@ static void parse_command_reply(void) static void pipe_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { - if (0 == nread) { + BUFFER *response = client->data; + + if (0 == nread) fprintf(stderr, "%s: Zero bytes read by command pipe.\n", __func__); - } else if (UV_EOF == nread) { -// fprintf(stderr, "EOF found in command pipe.\n"); - parse_command_reply(); - } else if (nread < 0) { - fprintf(stderr, "%s: %s\n", __func__, uv_strerror(nread)); + else if (UV_EOF == nread) + parse_command_reply(response); + else if (nread < 0) { + fprintf(stderr, "%s: %s\n", __func__, uv_strerror(nread)); + (void)uv_read_stop((uv_stream_t *)client); } + else + buffer_fast_rawcat(response, buf->base, nread); - if (nread < 0) { /* stop stream due to EOF or error */ - (void)uv_read_stop((uv_stream_t *)client); - } else if (nread) { - size_t to_copy; - - to_copy = MIN((unsigned int) nread, MAX_COMMAND_LENGTH - 1 - response_string_size); - memcpy(response_string + response_string_size, buf->base, to_copy); - response_string_size += to_copy; - response_string[response_string_size] = '\0'; - } - if (buf && buf->len) { + if (buf && buf->len) free(buf->base); - } } static void alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) @@ -104,8 +96,7 @@ static void shutdown_cb(uv_shutdown_t* req, int status) (void)status; /* receive reply */ - response_string_size = 0; - response_string[0] = '\0'; + client_pipe.data = req->data; ret = uv_read_start((uv_stream_t *)&client_pipe, alloc_cb, pipe_read_cb); if (ret) { @@ -113,16 +104,17 @@ static void shutdown_cb(uv_shutdown_t* req, int status) uv_close((uv_handle_t *)&client_pipe, NULL); return; } - } static void pipe_write_cb(uv_write_t* req, int status) { int ret; - (void)req; (void)status; + uv_pipe_t *clientp = req->data; + shutdown_req.data = clientp->data; + ret = uv_shutdown(&shutdown_req, (uv_stream_t *)&client_pipe, shutdown_cb); if (ret) { fprintf(stderr, "uv_shutdown(): %s\n", uv_strerror(ret)); @@ -144,10 +136,11 @@ static void connect_cb(uv_connect_t* req, int status) exit(-1); } if (0 == command_string_size) { - s = fgets(command_string, MAX_COMMAND_LENGTH, stdin); + s = fgets(command_string, MAX_COMMAND_LENGTH - 1, stdin); } (void)s; /* We don't need input to communicate with the server */ command_string_size = strlen(command_string); + client_pipe.data = req->data; write_req.data = &client_pipe; write_buf.base = command_string; @@ -191,11 +184,13 @@ int main(int argc, char **argv) } } + req.data = buffer_create(128, NULL); uv_pipe_connect(&req, &client_pipe, PIPENAME, connect_cb); uv_run(loop, UV_RUN_DEFAULT); uv_close((uv_handle_t *)&client_pipe, NULL); + buffer_free(client_pipe.data); return exit_status; } diff --git a/daemon/commands.c b/daemon/commands.c index 377a4002f3..fcb75b71c9 100644 --- a/daemon/commands.c +++ b/daemon/commands.c @@ -47,6 +47,7 @@ static cmd_status_t cmd_write_config_execute(char *args, char **message); static cmd_status_t cmd_ping_execute(char *args, char **message); static cmd_status_t cmd_aclk_state(char *args, char **message); static cmd_status_t cmd_version(char *args, char **message); +static cmd_status_t cmd_dumpconfig(char *args, char **message); static command_info_t command_info_array[] = { {"help", cmd_help_execute, CMD_TYPE_HIGH_PRIORITY}, // show help menu @@ -61,7 +62,8 @@ static command_info_t command_info_array[] = { {"write-config", cmd_write_config_execute, CMD_TYPE_ORTHOGONAL}, {"ping", cmd_ping_execute, CMD_TYPE_ORTHOGONAL}, {"aclk-state", cmd_aclk_state, CMD_TYPE_ORTHOGONAL}, - {"version", cmd_version, CMD_TYPE_ORTHOGONAL} + {"version", cmd_version, CMD_TYPE_ORTHOGONAL}, + {"dumpconfig", cmd_dumpconfig, CMD_TYPE_ORTHOGONAL} }; /* Mutexes for commands of type CMD_TYPE_ORTHOGONAL */ @@ -127,6 +129,8 @@ static cmd_status_t cmd_help_execute(char *args, char **message) " Return with 'pong' if agent is alive.\n" "aclk-state [json]\n" " Returns current state of ACLK and Cloud connection. (optionally in json).\n" + "dumpconfig\n" + " Returns the current netdata.conf on stdout.\n" "version\n" " Returns the netdata version.\n", MAX_COMMAND_LENGTH - 1); @@ -330,6 +334,17 @@ static cmd_status_t cmd_version(char *args, char **message) return CMD_STATUS_SUCCESS; } +static cmd_status_t cmd_dumpconfig(char *args, char **message) +{ + (void)args; + + BUFFER *wb = buffer_create(1024, NULL); + config_generate(wb, 0); + *message = strdupz(buffer_tostring(wb)); + buffer_free(wb); + return CMD_STATUS_SUCCESS; +} + static void cmd_lock_exclusive(unsigned index) { (void)index; @@ -393,32 +408,30 @@ static void pipe_write_cb(uv_write_t* req, int status) uv_close((uv_handle_t *)client, pipe_close_cb); --clients; - freez(client->data); + buffer_free(client->data); info("Command Clients = %u\n", clients); } -static inline void add_char_to_command_reply(char *reply_string, unsigned *reply_string_size, char character) +static inline void add_char_to_command_reply(BUFFER *reply_string, unsigned *reply_string_size, char character) { - reply_string[(*reply_string_size)++] = character; + buffer_fast_charcat(reply_string, character); + *reply_string_size +=1; } -static inline void add_string_to_command_reply(char *reply_string, unsigned *reply_string_size, char *str) +static inline void add_string_to_command_reply(BUFFER *reply_string, unsigned *reply_string_size, char *str) { unsigned len; len = strlen(str); - - if (MAX_COMMAND_LENGTH - 1 < len + *reply_string_size) - len = MAX_COMMAND_LENGTH - *reply_string_size - 1; - - strncpyz(reply_string + *reply_string_size, str, len); + buffer_fast_strcat(reply_string, str, len); *reply_string_size += len; } static void send_command_reply(struct command_context *cmd_ctx, cmd_status_t status, char *message) { int ret; - char *reply_string = mallocz(MAX_COMMAND_LENGTH); + BUFFER *reply_string = buffer_create(128, NULL); + char exit_status_string[MAX_EXIT_STATUS_LENGTH + 1] = {'\0', }; unsigned reply_string_size = 0; uv_buf_t write_buf; @@ -436,13 +449,12 @@ static void send_command_reply(struct command_context *cmd_ctx, cmd_status_t sta cmd_ctx->write_req.data = client; client->data = reply_string; - write_buf.base = reply_string; + write_buf.base = reply_string->buffer; write_buf.len = reply_string_size; ret = uv_write(&cmd_ctx->write_req, (uv_stream_t *)client, &write_buf, 1, pipe_write_cb); if (ret) { error("uv_write(): %s", uv_strerror(ret)); } - info("COMMAND: Sending reply: \"%s\"", reply_string); } cmd_status_t execute_command(cmd_t idx, char *args, char **message) diff --git a/daemon/commands.h b/daemon/commands.h index 78bdcc779a..43a0ef96b6 100644 --- a/daemon/commands.h +++ b/daemon/commands.h @@ -26,6 +26,7 @@ typedef enum cmd { CMD_PING, CMD_ACLK_STATE, CMD_VERSION, + CMD_DUMPCONFIG, CMD_TOTAL_COMMANDS } cmd_t; diff --git a/libnetdata/buffer/buffer.h b/libnetdata/buffer/buffer.h index 83c2a38dd0..f5f83bc2ae 100644 --- a/libnetdata/buffer/buffer.h +++ b/libnetdata/buffer/buffer.h @@ -152,6 +152,35 @@ static inline void _buffer_json_depth_pop(BUFFER *wb) { wb->json.depth--; } +static inline void buffer_fast_charcat(BUFFER *wb, const char c) { + + buffer_need_bytes(wb, 2); + *(&wb->buffer[wb->len]) = c; + wb->len += 1; + wb->buffer[wb->len] = '\0'; + + buffer_overflow_check(wb); +} + +static inline void buffer_fast_rawcat(BUFFER *wb, const char *txt, size_t len) { + if(unlikely(!txt || !*txt || !len)) return; + + buffer_need_bytes(wb, len + 1); + + const char *t = txt; + const char *e = &txt[len]; + + char *d = &wb->buffer[wb->len]; + + while(t != e) + *d++ = *t++; + + wb->len += len; + wb->buffer[wb->len] = '\0'; + + buffer_overflow_check(wb); +} + static inline void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) { if(unlikely(!txt || !*txt || !len)) return;