Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../asfd.h"
4 : #include "../../async.h"
5 : #include "../../bu.h"
6 : #include "../../cstat.h"
7 : #include "../../conffile.h"
8 : #include "../../handy.h"
9 : #include "../../iobuf.h"
10 : #include "../../log.h"
11 : #include "cstat.h"
12 : #include "json_output.h"
13 : #include "status_server.h"
14 :
15 6 : static int parse_cntr_data(const char *buf, struct cstat *clist)
16 : {
17 6 : int bno=0;
18 6 : int ret=-1;
19 6 : char *cname=NULL;
20 6 : struct cstat *c=NULL;
21 6 : char *path=NULL;
22 6 : char *dp=NULL;
23 6 : pid_t pid=-1;
24 :
25 : // Skip the type.
26 6 : if(!(dp=strchr(buf, '\t')))
27 : return 0;
28 5 : dp++;
29 :
30 5 : if(extract_client_pid_bno(dp, &cname, &pid, &bno))
31 : return -1;
32 5 : if(!cname)
33 : return 0;
34 :
35 : // Find the array entry for this client,
36 : // and add the detail from the parent to it.
37 3 : for(c=clist; c; c=c->next)
38 : {
39 3 : struct cntr *cntr=NULL;
40 3 : if(strcmp(c->name, cname))
41 2 : continue;
42 1 : cstat_set_run_status(c, RUN_STATUS_RUNNING);
43 :
44 : // Find the cntr entry for this client/pid.
45 1 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
46 0 : if(cntr->pid==pid)
47 : break;
48 1 : if(!cntr)
49 : {
50 : // Need to allocate a new cntr.
51 1 : if(!(cntr=cntr_alloc())
52 1 : || cntr_init(cntr, cname, pid))
53 : goto end;
54 1 : cstat_add_cntr_to_list(c, cntr);
55 : }
56 1 : if(str_to_cntr(buf, cntr, &path))
57 : goto end;
58 : }
59 :
60 : // FIX THIS: Do something with path.
61 :
62 : ret=0;
63 : end:
64 5 : free_w(&cname);
65 5 : free_w(&path);
66 5 : return ret;
67 : }
68 :
69 4 : static void clean_up_cntrs(struct cstat *clist)
70 : {
71 : struct cstat *c;
72 16 : for(c=clist; c; c=c->next)
73 : {
74 : struct cntr *cntr=NULL;
75 24 : for(cntr=c->cntrs; cntr; )
76 : {
77 0 : if(cntr->found)
78 : {
79 0 : cntr=cntr->next;
80 0 : continue;
81 : }
82 0 : cstat_remove_cntr_from_list(c, cntr);
83 0 : cntr_free(&cntr);
84 0 : if(c->cntrs)
85 0 : cntr=c->cntrs;
86 : }
87 : }
88 4 : }
89 :
90 9 : static int parse_clients_list(char *buf, struct cstat *clist)
91 : {
92 9 : char *tok=NULL;
93 : struct cstat *c;
94 :
95 9 : if(!clist)
96 : return 0;
97 :
98 : // Do not need the first token.
99 4 : if(!(tok=strtok(buf, "\t\n")))
100 : return 0;
101 12 : for(c=clist; c; c=c->next)
102 : {
103 : struct cntr *cntr;
104 12 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
105 0 : cntr->found=0;
106 12 : cstat_set_run_status(c, RUN_STATUS_IDLE);
107 : }
108 :
109 7 : while((tok=strtok(NULL, "\t\n")))
110 : {
111 3 : int bno=0;
112 3 : pid_t pid=-1;
113 3 : char *cname=NULL;
114 3 : if(extract_client_pid_bno(tok, &cname, &pid, &bno))
115 0 : return -1;
116 11 : for(c=clist; c; c=c->next)
117 : {
118 : struct cntr *cntr;
119 7 : if(strcmp(c->name, cname))
120 4 : continue;
121 3 : cstat_set_run_status(c, RUN_STATUS_RUNNING);
122 3 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
123 0 : if(cntr->pid==pid)
124 : break;
125 3 : if(cntr)
126 : {
127 0 : cntr->found=1;
128 0 : cntr->bno=bno;
129 : }
130 : break;
131 : }
132 3 : free_w(&cname);
133 : }
134 :
135 4 : clean_up_cntrs(clist);
136 :
137 4 : return 0;
138 : }
139 :
140 : #ifndef UTEST
141 : static
142 : #endif
143 18 : int parse_parent_data(char *buf, struct cstat *clist)
144 : {
145 18 : if(!buf || !*buf)
146 : return 0;
147 :
148 17 : if(!strncmp(buf, "cntr", strlen("cntr")))
149 : {
150 6 : if(parse_cntr_data(buf, clist))
151 : return -1;
152 : }
153 11 : else if(!strncmp(buf, "clients", strlen("clients")))
154 : {
155 9 : if(parse_clients_list(buf, clist))
156 : return -1;
157 : }
158 :
159 : return 0;
160 : }
161 :
162 0 : static char *get_str(const char **buf, const char *pre, int last)
163 : {
164 0 : size_t len=0;
165 0 : char *cp=NULL;
166 0 : char *copy=NULL;
167 0 : char *ret=NULL;
168 0 : if(!buf || !*buf) goto end;
169 0 : len=strlen(pre);
170 0 : if(strncmp(*buf, pre, len)
171 0 : || !(copy=strdup_w((*buf)+len, __func__)))
172 : goto end;
173 0 : if(!last && (cp=strchr(copy, ':'))) *cp='\0';
174 0 : *buf+=len+strlen(copy)+1;
175 0 : ret=strdup_w(copy, __func__);
176 : end:
177 0 : free_w(©);
178 0 : return ret;
179 : }
180 :
181 : /*
182 : void dump_cbno(struct cstat *clist, const char *msg)
183 : {
184 : if(!clist) return;
185 : printf("dump %s: %s\n", msg, clist->name);
186 : struct bu *b;
187 : for(b=clist->bu; b; b=b->prev)
188 : printf(" %d\n", b->bno);
189 : }
190 : */
191 :
192 : static int response_marker_start(struct asfd *srfd, const char *buf)
193 : {
194 0 : return json_send_msg(srfd, "response-start", buf);
195 : }
196 :
197 : static int response_marker_end(struct asfd *srfd, const char *buf)
198 : {
199 0 : return json_send_msg(srfd, "response-end", buf);
200 : }
201 :
202 0 : static int parse_client_data(struct asfd *srfd,
203 : struct cstat *clist, int monitor_browse_cache, long *peer_version)
204 : {
205 0 : int ret=0;
206 0 : char *command=NULL;
207 0 : char *client=NULL;
208 0 : char *backup=NULL;
209 0 : char *logfile=NULL;
210 0 : char *browse=NULL;
211 : const char *cp=NULL;
212 0 : struct cstat *cstat=NULL;
213 0 : struct bu *bu=NULL;
214 : static int response_markers=0;
215 0 : const char *cmd_result=NULL;
216 : //logp("got client data: '%s'\n", srfd->rbuf->buf);
217 :
218 0 : cp=srfd->rbuf->buf;
219 0 : command=get_str(&cp, "j:", 0);
220 0 : client=get_str(&cp, "c:", 0);
221 0 : backup=get_str(&cp, "b:", 0);
222 0 : logfile=get_str(&cp, "l:", 0);
223 0 : browse=get_str(&cp, "p:", 1);
224 :
225 0 : if(command)
226 : {
227 : size_t l;
228 0 : char peer_version_str[32]="peer_version=";
229 0 : l=strlen(peer_version_str);
230 0 : if(!strcmp(command, "pretty-print-on"))
231 : {
232 0 : json_set_pretty_print(1);
233 0 : cmd_result="Pretty print on";
234 : }
235 0 : else if(!strcmp(command, "pretty-print-off"))
236 : {
237 0 : json_set_pretty_print(0);
238 0 : cmd_result="Pretty print off";
239 : }
240 0 : else if(!strcmp(command, "response-markers-on"))
241 : {
242 0 : response_markers=1;
243 0 : cmd_result="Response markers on";
244 : }
245 0 : else if(!strcmp(command, "response-markers-off"))
246 : {
247 0 : response_markers=0;
248 0 : cmd_result="Response markers off";
249 : }
250 0 : else if(!strncmp(command, peer_version_str, l))
251 : {
252 0 : if(!(*peer_version=version_to_long(command+l)))
253 : goto error;
254 : cmd_result="Peer version updated";
255 : }
256 : else
257 : {
258 : cmd_result="Unknown command";
259 : }
260 : }
261 :
262 0 : if(response_markers
263 0 : && response_marker_start(srfd, srfd->rbuf->buf))
264 : goto error;
265 :
266 0 : if(cmd_result)
267 : {
268 0 : if(json_send_warn(srfd, cmd_result))
269 : goto error;
270 : goto end;
271 : }
272 :
273 0 : if(browse)
274 : {
275 0 : free_w(&logfile);
276 0 : if(!(logfile=strdup_w("manifest", __func__)))
277 : goto error;
278 0 : strip_trailing_slashes(&browse);
279 : }
280 :
281 : //dump_cbno(clist, "pcd");
282 :
283 0 : if(client && *client)
284 : {
285 0 : if(!(cstat=cstat_get_by_name(clist, client)))
286 : {
287 0 : char msg[256]="";
288 0 : snprintf(msg, sizeof(msg),
289 : "Could not find client: %s", client);
290 0 : if(json_send_warn(srfd, msg))
291 : goto error;
292 0 : goto end;
293 : }
294 :
295 0 : if(cstat_set_backup_list(cstat))
296 : {
297 0 : if(json_send_warn(srfd, "Could not get backup list"))
298 : goto error;
299 : goto end;
300 :
301 : }
302 : }
303 0 : if(cstat && backup)
304 : {
305 0 : unsigned long bno=0;
306 0 : if(!(bno=strtoul(backup, NULL, 10)))
307 : {
308 0 : if(json_send_warn(srfd, "Could not get backup number"))
309 : goto error;
310 : goto end;
311 : }
312 0 : for(bu=cstat->bu; bu; bu=bu->prev)
313 0 : if(bu->bno==bno) break;
314 :
315 0 : if(!bu)
316 : {
317 0 : if(json_send_warn(srfd, "Backup not found"))
318 : goto error;
319 : goto end;
320 : }
321 : }
322 0 : if(logfile)
323 : {
324 0 : if(strcmp(logfile, "manifest")
325 0 : && strcmp(logfile, "backup")
326 0 : && strcmp(logfile, "restore")
327 0 : && strcmp(logfile, "verify")
328 0 : && strcmp(logfile, "backup_stats")
329 0 : && strcmp(logfile, "restore_stats")
330 0 : && strcmp(logfile, "verify_stats"))
331 : {
332 0 : if(json_send_warn(srfd, "File not supported"))
333 : goto error;
334 : goto end;
335 : }
336 : }
337 : /*
338 : printf("client: %s\n", client?:"");
339 : printf("backup: %s\n", backup?:"");
340 : printf("logfile: %s\n", logfile?:"");
341 : */
342 0 : if(json_send(srfd, clist, cstat, bu, logfile, browse,
343 : monitor_browse_cache, *peer_version))
344 : goto error;
345 :
346 : goto end;
347 : error:
348 : ret=-1;
349 : end:
350 0 : if(response_markers
351 0 : && response_marker_end(srfd, srfd->rbuf->buf))
352 : goto error;
353 :
354 0 : free_w(&client);
355 0 : free_w(&backup);
356 0 : free_w(&logfile);
357 0 : free_w(&browse);
358 0 : return ret;
359 : }
360 :
361 0 : static int parse_data(struct asfd *asfd, struct cstat *clist,
362 : struct asfd *cfd, int monitor_browse_cache, long *peer_version)
363 : {
364 0 : if(asfd==cfd)
365 0 : return parse_client_data(asfd,
366 : clist, monitor_browse_cache, peer_version);
367 0 : return parse_parent_data(asfd->rbuf->buf, clist);
368 : }
369 :
370 : static int have_data_for_running_clients(struct cstat *clist)
371 : {
372 : struct cstat *c;
373 0 : for(c=clist; c; c=c->next)
374 : {
375 0 : if(c->run_status==RUN_STATUS_RUNNING)
376 : {
377 0 : if(!c->cntrs
378 0 : || c->cntrs->cntr_status==CNTR_STATUS_UNSET)
379 : return 0;
380 : }
381 : }
382 : return 1;
383 : }
384 :
385 : static int have_run_statuses(struct cstat *clist)
386 : {
387 : struct cstat *c;
388 0 : for(c=clist; c; c=c->next)
389 0 : if(c->permitted && c->run_status==RUN_STATUS_UNSET)
390 : return 0;
391 : return 1;
392 : }
393 :
394 0 : static int get_initial_data(struct async *as,
395 : struct cstat **clist,
396 : struct conf **monitor_cconfs,
397 : struct conf **globalcs, struct conf **cconfs,
398 : int monitor_browse_cache, long *peer_version)
399 : {
400 0 : int x=10;
401 0 : struct asfd *asfd=NULL;
402 :
403 0 : if(cstat_load_data_from_disk(clist, monitor_cconfs, globalcs, cconfs))
404 : return -1;
405 :
406 : // Try to get the initial data.
407 0 : while(x)
408 : {
409 : // Do not wait forever for running clients.
410 0 : if(!have_data_for_running_clients(*clist))
411 0 : x--;
412 0 : else if(have_run_statuses(*clist))
413 : return 0;
414 :
415 0 : if(as->read_write(as))
416 : {
417 0 : logp("Exiting main status server loop\n");
418 0 : return -1;
419 : }
420 0 : asfd=as->asfd->next;
421 0 : if(asfd->rbuf->buf)
422 : {
423 0 : if(parse_data(asfd, *clist,
424 : NULL, monitor_browse_cache, peer_version))
425 : {
426 0 : iobuf_free_content(asfd->rbuf);
427 0 : return -1;
428 : }
429 0 : iobuf_free_content(asfd->rbuf);
430 : }
431 : }
432 : return 0;
433 : }
434 :
435 0 : int status_server(struct async *as, struct conf **monitor_cconfs)
436 : {
437 0 : int ret=-1;
438 0 : int gotdata=0;
439 : struct asfd *asfd;
440 0 : struct cstat *clist=NULL;
441 0 : struct asfd *cfd=as->asfd; // Client.
442 0 : struct conf **cconfs=NULL;
443 0 : struct conf **globalcs=NULL;
444 0 : const char *conffile=get_string(monitor_cconfs[OPT_CONFFILE]);
445 0 : long peer_version=version_to_long(get_string(monitor_cconfs[OPT_PEER_VERSION]));
446 0 : int monitor_browse_cache=get_int(monitor_cconfs[OPT_MONITOR_BROWSE_CACHE]);
447 :
448 : // We need to load a fresh global conf so that the clients do not all
449 : // get settings from the monitor client. In particular, if protocol=0
450 : // in both burp-server.conf and the monitor burp.conf, the monitor
451 : // client gets protocol=1 from extra comms, and all the clients here
452 : // would end up getting protocol=1.
453 0 : if(!(globalcs=confs_alloc()))
454 : goto end;
455 0 : if(confs_init(globalcs)) return -1;
456 0 : if(conf_load_global_only(conffile, globalcs))
457 : return -1;
458 :
459 0 : if(!(cconfs=confs_alloc()))
460 : goto end;
461 :
462 0 : if(get_initial_data(as, &clist, monitor_cconfs,
463 : globalcs, cconfs, monitor_browse_cache, &peer_version))
464 : goto end;
465 :
466 : while(1)
467 : {
468 : // Take the opportunity to get data from the disk if nothing
469 : // was read from the fds.
470 0 : if(gotdata) gotdata=0;
471 0 : else if(cstat_load_data_from_disk(&clist, monitor_cconfs,
472 : globalcs, cconfs))
473 : goto end;
474 0 : if(as->read_write(as))
475 : {
476 0 : logp("Exiting main status server loop\n");
477 : break;
478 : }
479 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
480 0 : while(asfd->rbuf->buf)
481 : {
482 0 : gotdata=1;
483 0 : if(parse_data(asfd, clist,
484 : cfd, monitor_browse_cache, &peer_version)
485 0 : || asfd->parse_readbuf(asfd))
486 : goto end;
487 0 : iobuf_free_content(asfd->rbuf);
488 : }
489 : }
490 0 : ret=0;
491 : end:
492 : // FIX THIS: should free clist;
493 0 : confs_free(&globalcs);
494 0 : return ret;
495 : }
|