cli.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "cli.h"
  3. #include "daemon/pipename.h"
  4. void netdata_logger(ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) {
  5. va_list args;
  6. va_start(args, fmt);
  7. vfprintf(stderr, fmt, args );
  8. va_end(args);
  9. }
  10. #ifdef NETDATA_INTERNAL_CHECKS
  11. uint64_t debug_flags;
  12. void netdata_logger_fatal( const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt __maybe_unused, ... )
  13. {
  14. abort();
  15. };
  16. #endif
  17. #ifdef NETDATA_TRACE_ALLOCATIONS
  18. void *callocz_int(size_t nmemb, size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
  19. {
  20. void *p = calloc(nmemb, size);
  21. if (unlikely(!p)) {
  22. netdata_log_error("Cannot allocate %zu bytes of memory.", nmemb * size);
  23. exit(1);
  24. }
  25. return p;
  26. }
  27. void *mallocz_int(size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
  28. {
  29. void *p = malloc(size);
  30. if (unlikely(!p)) {
  31. netdata_log_error("Cannot allocate %zu bytes of memory.", size);
  32. exit(1);
  33. }
  34. return p;
  35. }
  36. void *reallocz_int(void *ptr, size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
  37. {
  38. void *p = realloc(ptr, size);
  39. if (unlikely(!p)) {
  40. netdata_log_error("Cannot allocate %zu bytes of memory.", size);
  41. exit(1);
  42. }
  43. return p;
  44. }
  45. void freez_int(void *ptr, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
  46. {
  47. free(ptr);
  48. }
  49. #else
  50. void freez(void *ptr) {
  51. free(ptr);
  52. }
  53. void *mallocz(size_t size) {
  54. void *p = malloc(size);
  55. if (unlikely(!p)) {
  56. netdata_log_error("Cannot allocate %zu bytes of memory.", size);
  57. exit(1);
  58. }
  59. return p;
  60. }
  61. void *callocz(size_t nmemb, size_t size) {
  62. void *p = calloc(nmemb, size);
  63. if (unlikely(!p)) {
  64. netdata_log_error("Cannot allocate %zu bytes of memory.", nmemb * size);
  65. exit(1);
  66. }
  67. return p;
  68. }
  69. void *reallocz(void *ptr, size_t size) {
  70. void *p = realloc(ptr, size);
  71. if (unlikely(!p)) {
  72. netdata_log_error("Cannot allocate %zu bytes of memory.", size);
  73. exit(1);
  74. }
  75. return p;
  76. }
  77. #endif
  78. int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
  79. if(unlikely(!n)) return 0;
  80. int size = vsnprintf(dst, n, fmt, args);
  81. dst[n - 1] = '\0';
  82. if (unlikely((size_t) size > n)) size = (int)n;
  83. return size;
  84. }
  85. static uv_pipe_t client_pipe;
  86. static uv_write_t write_req;
  87. static uv_shutdown_t shutdown_req;
  88. static char command_string[MAX_COMMAND_LENGTH];
  89. static unsigned command_string_size;
  90. static int exit_status;
  91. struct command_context {
  92. uv_work_t work;
  93. uv_stream_t *client;
  94. cmd_t idx;
  95. char *args;
  96. char *message;
  97. cmd_status_t status;
  98. };
  99. static void parse_command_reply(BUFFER *buf)
  100. {
  101. char *response_string = (char *) buffer_tostring(buf);
  102. unsigned response_string_size = buffer_strlen(buf);
  103. FILE *stream = NULL;
  104. char *pos;
  105. int syntax_error = 0;
  106. for (pos = response_string ;
  107. pos < response_string + response_string_size && !syntax_error ;
  108. ++pos) {
  109. /* Skip white-space characters */
  110. for ( ; isspace(*pos) && ('\0' != *pos); ++pos) {;}
  111. if ('\0' == *pos)
  112. continue;
  113. switch (*pos) {
  114. case CMD_PREFIX_EXIT_CODE:
  115. exit_status = atoi(++pos);
  116. break;
  117. case CMD_PREFIX_INFO:
  118. stream = stdout;
  119. break;
  120. case CMD_PREFIX_ERROR:
  121. stream = stderr;
  122. break;
  123. default:
  124. syntax_error = 1;
  125. fprintf(stderr, "Syntax error, failed to parse command response.\n");
  126. break;
  127. }
  128. if (stream) {
  129. fprintf(stream, "%s\n", ++pos);
  130. pos += strlen(pos);
  131. stream = NULL;
  132. }
  133. }
  134. }
  135. static void pipe_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
  136. {
  137. BUFFER *response = client->data;
  138. if (0 == nread)
  139. fprintf(stderr, "%s: Zero bytes read by command pipe.\n", __func__);
  140. else if (UV_EOF == nread)
  141. parse_command_reply(response);
  142. else if (nread < 0) {
  143. fprintf(stderr, "%s: %s\n", __func__, uv_strerror(nread));
  144. (void)uv_read_stop((uv_stream_t *)client);
  145. }
  146. else
  147. buffer_fast_rawcat(response, buf->base, nread);
  148. if (buf && buf->len)
  149. free(buf->base);
  150. }
  151. static void alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
  152. {
  153. (void)handle;
  154. buf->base = malloc(suggested_size);
  155. buf->len = suggested_size;
  156. }
  157. static void shutdown_cb(uv_shutdown_t* req, int status)
  158. {
  159. int ret;
  160. (void)req;
  161. (void)status;
  162. /* receive reply */
  163. client_pipe.data = req->data;
  164. ret = uv_read_start((uv_stream_t *)&client_pipe, alloc_cb, pipe_read_cb);
  165. if (ret) {
  166. fprintf(stderr, "uv_read_start(): %s\n", uv_strerror(ret));
  167. uv_close((uv_handle_t *)&client_pipe, NULL);
  168. return;
  169. }
  170. }
  171. static void pipe_write_cb(uv_write_t* req, int status)
  172. {
  173. int ret;
  174. (void)status;
  175. uv_pipe_t *clientp = req->data;
  176. shutdown_req.data = clientp->data;
  177. ret = uv_shutdown(&shutdown_req, (uv_stream_t *)&client_pipe, shutdown_cb);
  178. if (ret) {
  179. fprintf(stderr, "uv_shutdown(): %s\n", uv_strerror(ret));
  180. uv_close((uv_handle_t *)&client_pipe, NULL);
  181. return;
  182. }
  183. }
  184. static void connect_cb(uv_connect_t* req, int status)
  185. {
  186. int ret;
  187. uv_buf_t write_buf;
  188. char *s;
  189. (void)req;
  190. if (status) {
  191. fprintf(stderr, "uv_pipe_connect(): %s\n", uv_strerror(status));
  192. fprintf(stderr, "Make sure the netdata service is running.\n");
  193. exit(-1);
  194. }
  195. if (0 == command_string_size) {
  196. s = fgets(command_string, MAX_COMMAND_LENGTH - 1, stdin);
  197. }
  198. (void)s; /* We don't need input to communicate with the server */
  199. command_string_size = strlen(command_string);
  200. client_pipe.data = req->data;
  201. write_req.data = &client_pipe;
  202. write_buf.base = command_string;
  203. write_buf.len = command_string_size;
  204. ret = uv_write(&write_req, (uv_stream_t *)&client_pipe, &write_buf, 1, pipe_write_cb);
  205. if (ret) {
  206. fprintf(stderr, "uv_write(): %s\n", uv_strerror(ret));
  207. }
  208. // fprintf(stderr, "COMMAND: Sending command: \"%s\"\n", command_string);
  209. }
  210. int main(int argc, char **argv)
  211. {
  212. int ret, i;
  213. static uv_loop_t* loop;
  214. uv_connect_t req;
  215. exit_status = -1; /* default status for when there is no command response from server */
  216. loop = uv_default_loop();
  217. ret = uv_pipe_init(loop, &client_pipe, 1);
  218. if (ret) {
  219. fprintf(stderr, "uv_pipe_init(): %s\n", uv_strerror(ret));
  220. return exit_status;
  221. }
  222. command_string_size = 0;
  223. command_string[0] = '\0';
  224. for (i = 1 ; i < argc ; ++i) {
  225. size_t to_copy;
  226. to_copy = MIN(strlen(argv[i]), MAX_COMMAND_LENGTH - 1 - command_string_size);
  227. strncpy(command_string + command_string_size, argv[i], to_copy);
  228. command_string_size += to_copy;
  229. command_string[command_string_size] = '\0';
  230. if (command_string_size < MAX_COMMAND_LENGTH - 1) {
  231. command_string[command_string_size++] = ' ';
  232. } else {
  233. break;
  234. }
  235. }
  236. req.data = buffer_create(128, NULL);
  237. const char *pipename = daemon_pipename();
  238. uv_pipe_connect(&req, &client_pipe, pipename, connect_cb);
  239. uv_run(loop, UV_RUN_DEFAULT);
  240. uv_close((uv_handle_t *)&client_pipe, NULL);
  241. buffer_free(client_pipe.data);
  242. return exit_status;
  243. }