cli.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "cli.h"
  3. #include "libnetdata/required_dummies.h"
  4. static uv_pipe_t client_pipe;
  5. static uv_write_t write_req;
  6. static uv_shutdown_t shutdown_req;
  7. static char command_string[MAX_COMMAND_LENGTH];
  8. static unsigned command_string_size;
  9. static int exit_status;
  10. struct command_context {
  11. uv_work_t work;
  12. uv_stream_t *client;
  13. cmd_t idx;
  14. char *args;
  15. char *message;
  16. cmd_status_t status;
  17. };
  18. static void parse_command_reply(BUFFER *buf)
  19. {
  20. char *response_string = (char *) buffer_tostring(buf);
  21. unsigned response_string_size = buffer_strlen(buf);
  22. FILE *stream = NULL;
  23. char *pos;
  24. int syntax_error = 0;
  25. for (pos = response_string ;
  26. pos < response_string + response_string_size && !syntax_error ;
  27. ++pos) {
  28. /* Skip white-space characters */
  29. for ( ; isspace(*pos) && ('\0' != *pos); ++pos) {;}
  30. if ('\0' == *pos)
  31. continue;
  32. switch (*pos) {
  33. case CMD_PREFIX_EXIT_CODE:
  34. exit_status = atoi(++pos);
  35. break;
  36. case CMD_PREFIX_INFO:
  37. stream = stdout;
  38. break;
  39. case CMD_PREFIX_ERROR:
  40. stream = stderr;
  41. break;
  42. default:
  43. syntax_error = 1;
  44. fprintf(stderr, "Syntax error, failed to parse command response.\n");
  45. break;
  46. }
  47. if (stream) {
  48. fprintf(stream, "%s\n", ++pos);
  49. pos += strlen(pos);
  50. stream = NULL;
  51. }
  52. }
  53. }
  54. static void pipe_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
  55. {
  56. BUFFER *response = client->data;
  57. if (0 == nread)
  58. fprintf(stderr, "%s: Zero bytes read by command pipe.\n", __func__);
  59. else if (UV_EOF == nread)
  60. parse_command_reply(response);
  61. else if (nread < 0) {
  62. fprintf(stderr, "%s: %s\n", __func__, uv_strerror(nread));
  63. (void)uv_read_stop((uv_stream_t *)client);
  64. }
  65. else
  66. buffer_fast_rawcat(response, buf->base, nread);
  67. if (buf && buf->len)
  68. free(buf->base);
  69. }
  70. static void alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
  71. {
  72. (void)handle;
  73. buf->base = malloc(suggested_size);
  74. buf->len = suggested_size;
  75. }
  76. static void shutdown_cb(uv_shutdown_t* req, int status)
  77. {
  78. int ret;
  79. (void)req;
  80. (void)status;
  81. /* receive reply */
  82. client_pipe.data = req->data;
  83. ret = uv_read_start((uv_stream_t *)&client_pipe, alloc_cb, pipe_read_cb);
  84. if (ret) {
  85. fprintf(stderr, "uv_read_start(): %s\n", uv_strerror(ret));
  86. uv_close((uv_handle_t *)&client_pipe, NULL);
  87. return;
  88. }
  89. }
  90. static void pipe_write_cb(uv_write_t* req, int status)
  91. {
  92. int ret;
  93. (void)status;
  94. uv_pipe_t *clientp = req->data;
  95. shutdown_req.data = clientp->data;
  96. ret = uv_shutdown(&shutdown_req, (uv_stream_t *)&client_pipe, shutdown_cb);
  97. if (ret) {
  98. fprintf(stderr, "uv_shutdown(): %s\n", uv_strerror(ret));
  99. uv_close((uv_handle_t *)&client_pipe, NULL);
  100. return;
  101. }
  102. }
  103. static void connect_cb(uv_connect_t* req, int status)
  104. {
  105. int ret;
  106. uv_buf_t write_buf;
  107. char *s;
  108. (void)req;
  109. if (status) {
  110. fprintf(stderr, "uv_pipe_connect(): %s\n", uv_strerror(status));
  111. fprintf(stderr, "Make sure the netdata service is running.\n");
  112. exit(-1);
  113. }
  114. if (0 == command_string_size) {
  115. s = fgets(command_string, MAX_COMMAND_LENGTH - 1, stdin);
  116. }
  117. (void)s; /* We don't need input to communicate with the server */
  118. command_string_size = strlen(command_string);
  119. client_pipe.data = req->data;
  120. write_req.data = &client_pipe;
  121. write_buf.base = command_string;
  122. write_buf.len = command_string_size;
  123. ret = uv_write(&write_req, (uv_stream_t *)&client_pipe, &write_buf, 1, pipe_write_cb);
  124. if (ret) {
  125. fprintf(stderr, "uv_write(): %s\n", uv_strerror(ret));
  126. }
  127. // fprintf(stderr, "COMMAND: Sending command: \"%s\"\n", command_string);
  128. }
  129. int main(int argc, char **argv)
  130. {
  131. int ret, i;
  132. static uv_loop_t* loop;
  133. uv_connect_t req;
  134. exit_status = -1; /* default status for when there is no command response from server */
  135. loop = uv_default_loop();
  136. ret = uv_pipe_init(loop, &client_pipe, 1);
  137. if (ret) {
  138. fprintf(stderr, "uv_pipe_init(): %s\n", uv_strerror(ret));
  139. return exit_status;
  140. }
  141. command_string_size = 0;
  142. command_string[0] = '\0';
  143. for (i = 1 ; i < argc ; ++i) {
  144. size_t to_copy;
  145. to_copy = MIN(strlen(argv[i]), MAX_COMMAND_LENGTH - 1 - command_string_size);
  146. strncpyz(command_string + command_string_size, argv[i], to_copy);
  147. command_string_size += to_copy;
  148. if (command_string_size < MAX_COMMAND_LENGTH - 1) {
  149. command_string[command_string_size++] = ' ';
  150. } else {
  151. break;
  152. }
  153. }
  154. req.data = buffer_create(128, NULL);
  155. uv_pipe_connect(&req, &client_pipe, PIPENAME, connect_cb);
  156. uv_run(loop, UV_RUN_DEFAULT);
  157. uv_close((uv_handle_t *)&client_pipe, NULL);
  158. buffer_free(client_pipe.data);
  159. return exit_status;
  160. }