cli.c 7.8 KB

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