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