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 12 : 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 0 : static int parse_client_data(struct asfd *srfd,
193 : struct cstat *clist, int monitor_browse_cache, long *peer_version)
194 : {
195 0 : int ret=0;
196 0 : char *command=NULL;
197 0 : char *client=NULL;
198 0 : char *backup=NULL;
199 0 : char *logfile=NULL;
200 0 : char *browse=NULL;
201 0 : const char *cp=NULL;
202 0 : struct cstat *cstat=NULL;
203 0 : struct bu *bu=NULL;
204 : //logp("got client data: '%s'\n", srfd->rbuf->buf);
205 :
206 0 : cp=srfd->rbuf->buf;
207 :
208 0 : command=get_str(&cp, "j:", 0);
209 0 : client=get_str(&cp, "c:", 0);
210 0 : backup=get_str(&cp, "b:", 0);
211 0 : logfile=get_str(&cp, "l:", 0);
212 0 : browse=get_str(&cp, "p:", 1);
213 :
214 0 : if(command)
215 : {
216 : size_t l;
217 0 : char peer_version_str[32]="peer_version=";
218 0 : l=strlen(peer_version_str);
219 0 : if(!strcmp(command, "pretty-print-on"))
220 : {
221 0 : json_set_pretty_print(1);
222 0 : if(json_send_warn(srfd, "Pretty print on"))
223 : goto error;
224 : }
225 0 : else if(!strcmp(command, "pretty-print-off"))
226 : {
227 0 : json_set_pretty_print(0);
228 0 : if(json_send_warn(srfd, "Pretty print off"))
229 : goto error;
230 : }
231 0 : else if(!strncmp(command, peer_version_str, l))
232 : {
233 0 : if(!(*peer_version=version_to_long(command+l)))
234 : goto error;
235 : }
236 : else
237 : {
238 0 : if(json_send_warn(srfd, "Unknown command"))
239 : goto error;
240 : }
241 0 : goto end;
242 : }
243 :
244 0 : if(browse)
245 : {
246 0 : free_w(&logfile);
247 0 : if(!(logfile=strdup_w("manifest", __func__)))
248 : goto error;
249 0 : strip_trailing_slashes(&browse);
250 : }
251 :
252 : //dump_cbno(clist, "pcd");
253 :
254 0 : if(client && *client)
255 : {
256 0 : if(!(cstat=cstat_get_by_name(clist, client)))
257 : {
258 0 : char msg[256]="";
259 0 : snprintf(msg, sizeof(msg),
260 : "Could not find client: %s", client);
261 0 : if(json_send_warn(srfd, msg))
262 : goto error;
263 0 : goto end;
264 : }
265 :
266 0 : if(cstat_set_backup_list(cstat))
267 : {
268 0 : if(json_send_warn(srfd, "Could not get backup list"))
269 : goto error;
270 : goto end;
271 :
272 : }
273 : }
274 0 : if(cstat && backup)
275 : {
276 0 : unsigned long bno=0;
277 0 : if(!(bno=strtoul(backup, NULL, 10)))
278 : {
279 0 : if(json_send_warn(srfd, "Could not get backup number"))
280 : goto error;
281 : goto end;
282 : }
283 0 : for(bu=cstat->bu; bu; bu=bu->prev)
284 0 : if(bu->bno==bno) break;
285 :
286 0 : if(!bu)
287 : {
288 0 : if(json_send_warn(srfd, "Backup not found"))
289 : goto error;
290 : goto end;
291 : }
292 : }
293 0 : if(logfile)
294 : {
295 0 : if(strcmp(logfile, "manifest")
296 0 : && strcmp(logfile, "backup")
297 0 : && strcmp(logfile, "restore")
298 0 : && strcmp(logfile, "verify")
299 0 : && strcmp(logfile, "backup_stats")
300 0 : && strcmp(logfile, "restore_stats")
301 0 : && strcmp(logfile, "verify_stats"))
302 : {
303 0 : if(json_send_warn(srfd, "File not supported"))
304 : goto error;
305 : goto end;
306 : }
307 : }
308 : /*
309 : printf("client: %s\n", client?:"");
310 : printf("backup: %s\n", backup?:"");
311 : printf("logfile: %s\n", logfile?:"");
312 : */
313 0 : if(json_send(srfd, clist, cstat, bu, logfile, browse,
314 : monitor_browse_cache, *peer_version))
315 : goto error;
316 :
317 : goto end;
318 : error:
319 : ret=-1;
320 : end:
321 0 : free_w(&client);
322 0 : free_w(&backup);
323 0 : free_w(&logfile);
324 0 : free_w(&browse);
325 0 : return ret;
326 : }
327 :
328 0 : static int parse_data(struct asfd *asfd, struct cstat *clist,
329 : struct asfd *cfd, int monitor_browse_cache, long *peer_version)
330 : {
331 0 : if(asfd==cfd)
332 0 : return parse_client_data(asfd,
333 : clist, monitor_browse_cache, peer_version);
334 0 : return parse_parent_data(asfd->rbuf->buf, clist);
335 : }
336 :
337 : static int have_data_for_running_clients(struct cstat *clist)
338 : {
339 : struct cstat *c;
340 0 : for(c=clist; c; c=c->next)
341 : {
342 0 : if(c->run_status==RUN_STATUS_RUNNING)
343 : {
344 0 : if(!c->cntrs
345 0 : || c->cntrs->cntr_status==CNTR_STATUS_UNSET)
346 : return 0;
347 : }
348 : }
349 : return 1;
350 : }
351 :
352 : static int have_run_statuses(struct cstat *clist)
353 : {
354 : struct cstat *c;
355 0 : for(c=clist; c; c=c->next)
356 0 : if(c->permitted && c->run_status==RUN_STATUS_UNSET)
357 : return 0;
358 : return 1;
359 : }
360 :
361 0 : static int get_initial_data(struct async *as,
362 : struct cstat **clist,
363 : struct conf **monitor_cconfs,
364 : struct conf **globalcs, struct conf **cconfs,
365 : int monitor_browse_cache, long *peer_version)
366 : {
367 0 : int x=10;
368 0 : struct asfd *asfd=NULL;
369 :
370 0 : if(cstat_load_data_from_disk(clist, monitor_cconfs, globalcs, cconfs))
371 : return -1;
372 :
373 : // Try to get the initial data.
374 0 : while(x)
375 : {
376 : // Do not wait forever for running clients.
377 0 : if(!have_data_for_running_clients(*clist))
378 0 : x--;
379 0 : else if(have_run_statuses(*clist))
380 : return 0;
381 :
382 0 : if(as->read_write(as))
383 : {
384 0 : logp("Exiting main status server loop\n");
385 0 : return -1;
386 : }
387 0 : asfd=as->asfd->next;
388 0 : if(asfd->rbuf->buf)
389 : {
390 0 : if(parse_data(asfd, *clist,
391 : NULL, monitor_browse_cache, peer_version))
392 : {
393 0 : iobuf_free_content(asfd->rbuf);
394 0 : return -1;
395 : }
396 0 : iobuf_free_content(asfd->rbuf);
397 : }
398 : }
399 : return 0;
400 : }
401 :
402 0 : int status_server(struct async *as, struct conf **monitor_cconfs)
403 : {
404 0 : int ret=-1;
405 0 : int gotdata=0;
406 : struct asfd *asfd;
407 0 : struct cstat *clist=NULL;
408 0 : struct asfd *cfd=as->asfd; // Client.
409 0 : struct conf **cconfs=NULL;
410 0 : struct conf **globalcs=NULL;
411 0 : const char *conffile=get_string(monitor_cconfs[OPT_CONFFILE]);
412 0 : long peer_version=version_to_long(get_string(monitor_cconfs[OPT_PEER_VERSION]));
413 0 : int monitor_browse_cache=get_int(monitor_cconfs[OPT_MONITOR_BROWSE_CACHE]);
414 :
415 : // We need to load a fresh global conf so that the clients do not all
416 : // get settings from the monitor client. In particular, if protocol=0
417 : // in both burp-server.conf and the monitor burp.conf, the monitor
418 : // client gets protocol=1 from extra comms, and all the clients here
419 : // would end up getting protocol=1.
420 0 : if(!(globalcs=confs_alloc()))
421 : goto end;
422 0 : if(confs_init(globalcs)) return -1;
423 0 : if(conf_load_global_only(conffile, globalcs))
424 : return -1;
425 :
426 0 : if(!(cconfs=confs_alloc()))
427 : goto end;
428 :
429 0 : if(get_initial_data(as, &clist, monitor_cconfs,
430 : globalcs, cconfs, monitor_browse_cache, &peer_version))
431 : goto end;
432 :
433 : while(1)
434 : {
435 : // Take the opportunity to get data from the disk if nothing
436 : // was read from the fds.
437 0 : if(gotdata) gotdata=0;
438 0 : else if(cstat_load_data_from_disk(&clist, monitor_cconfs,
439 : globalcs, cconfs))
440 : goto end;
441 0 : if(as->read_write(as))
442 : {
443 0 : logp("Exiting main status server loop\n");
444 : break;
445 : }
446 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
447 0 : while(asfd->rbuf->buf)
448 : {
449 0 : gotdata=1;
450 0 : if(parse_data(asfd, clist,
451 : cfd, monitor_browse_cache, &peer_version)
452 0 : || asfd->parse_readbuf(asfd))
453 : goto end;
454 0 : iobuf_free_content(asfd->rbuf);
455 : }
456 : }
457 0 : ret=0;
458 : end:
459 : // FIX THIS: should free clist;
460 0 : confs_free(&globalcs);
461 0 : return ret;
462 : }
|