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 "../../handy.h"
8 : #include "../../iobuf.h"
9 : #include "../../log.h"
10 : #include "json_input.h"
11 : #include "lline.h"
12 : #include "sel.h"
13 : #ifdef HAVE_WIN32
14 : #include <yajl/yajl_parse.h>
15 : #else
16 : #include "../../yajl/api/yajl_parse.h"
17 : #endif
18 :
19 : static int map_depth=0;
20 :
21 : static unsigned long number=0;
22 : static char *timestamp=NULL;
23 : static uint16_t flags=0;
24 : static struct cstat *cnew=NULL;
25 : static struct cstat *current=NULL;
26 : static struct cstat **cslist=NULL;
27 : static struct cntr_ent *cntr_ent=NULL;
28 : static char lastkey[32]="";
29 : static int in_backups=0;
30 : static int in_flags=0;
31 : static int in_counters=0;
32 : static int in_logslist=0;
33 : static int in_log_content=0;
34 : static struct bu **sselbu=NULL;
35 : static struct lline *ll_list=NULL;
36 : static struct lline **sllines=NULL;
37 :
38 : static int is_wrap(const char *val, const char *key, uint16_t bit)
39 : {
40 815 : if(!strcmp(val, key))
41 : {
42 180 : flags|=bit;
43 : return 1;
44 : }
45 : return 0;
46 : }
47 :
48 370 : static int input_integer(void *ctx, long long val)
49 : {
50 370 : if(in_counters)
51 : {
52 60 : if(!strcmp(lastkey, "count"))
53 : {
54 60 : if(!cntr_ent) goto error;
55 60 : cntr_ent->count=(uint64_t)val;
56 : }
57 0 : else if(!strcmp(lastkey, "changed"))
58 : {
59 0 : if(!cntr_ent) goto error;
60 0 : cntr_ent->changed=(uint64_t)val;
61 : }
62 0 : else if(!strcmp(lastkey, "same"))
63 : {
64 0 : if(!cntr_ent) goto error;
65 0 : cntr_ent->same=(uint64_t)val;
66 : }
67 0 : else if(!strcmp(lastkey, "deleted"))
68 : {
69 0 : if(!cntr_ent) goto error;
70 0 : cntr_ent->deleted=(uint64_t)val;
71 : }
72 0 : else if(!strcmp(lastkey, "scanned"))
73 : {
74 0 : if(!cntr_ent) goto error;
75 0 : cntr_ent->phase1=(uint64_t)val;
76 : }
77 : else
78 : {
79 : goto error;
80 : }
81 : return 1;
82 : }
83 310 : else if(in_backups && !in_flags && !in_counters && !in_logslist)
84 : {
85 230 : if(!current) goto error;
86 230 : if(!strcmp(lastkey, "number"))
87 : {
88 115 : number=(unsigned long)val;
89 115 : return 1;
90 : }
91 115 : else if(!strcmp(lastkey, "timestamp"))
92 : {
93 : time_t t;
94 115 : t=(unsigned long)val;
95 115 : free_w(×tamp);
96 115 : if(!(timestamp=strdup_w(getdatestr(t), __func__)))
97 : return 0;
98 115 : return 1;
99 : }
100 : }
101 : else
102 : {
103 80 : if(!strcmp(lastkey, "protocol"))
104 : {
105 : return 1;
106 : }
107 : }
108 : error:
109 0 : logp("Unexpected integer: %s %llu\n", lastkey, val);
110 0 : return 0;
111 : }
112 :
113 495 : static int input_string(void *ctx, const unsigned char *val, size_t len)
114 : {
115 : char *str;
116 495 : if(!(str=(char *)malloc_w(len+2, __func__)))
117 : return 0;
118 495 : snprintf(str, len+1, "%s", val);
119 :
120 495 : if(in_counters)
121 : {
122 120 : if(!strcmp(lastkey, "name"))
123 : {
124 : // Ignore 'name' in a counters object. We use 'type'
125 : // instead.
126 : }
127 60 : else if(!strcmp(lastkey, "type"))
128 : {
129 60 : if(!current) goto error;
130 60 : cntr_ent=current->cntr->ent[(uint8_t)*str];
131 : }
132 : else
133 : {
134 : goto error;
135 : }
136 : goto end;
137 : }
138 375 : else if(!strcmp(lastkey, "name"))
139 : {
140 80 : if(cnew) goto error;
141 80 : if(!(current=cstat_get_by_name(*cslist, str)))
142 : {
143 64 : if(!(cnew=cstat_alloc())
144 32 : || cstat_init_with_cntr(cnew, str, NULL))
145 : goto error;
146 32 : current=cnew;
147 : }
148 : goto end;
149 : }
150 295 : else if(!strcmp(lastkey, "labels"))
151 : {
152 30 : if(!current) goto error;
153 : goto end;
154 : }
155 265 : else if(!strcmp(lastkey, "run_status"))
156 : {
157 80 : if(!current) goto error;
158 80 : current->run_status=run_str_to_status(str);
159 80 : goto end;
160 : }
161 185 : else if(!strcmp(lastkey, "phase"))
162 : {
163 0 : if(!current) goto error;
164 0 : current->cntr->cntr_status=cntr_str_to_status(str);
165 0 : goto end;
166 : }
167 185 : else if(!strcmp(lastkey, "flags"))
168 : {
169 180 : if(!current) goto error;
170 360 : if(is_wrap(str, "hardlinked", BU_HARDLINKED)
171 350 : || is_wrap(str, "deletable", BU_DELETABLE)
172 300 : || is_wrap(str, "working", BU_WORKING)
173 270 : || is_wrap(str, "finishing", BU_FINISHING)
174 240 : || is_wrap(str, "current", BU_CURRENT)
175 290 : || is_wrap(str, "manifest", BU_MANIFEST))
176 : goto end;
177 : }
178 5 : else if(!strcmp(lastkey, "counters")) // Do we need this?
179 : {
180 : goto end;
181 : }
182 5 : else if(!strcmp(lastkey, "list"))
183 : {
184 0 : if(is_wrap(str, "backup", BU_LOG_BACKUP)
185 0 : || is_wrap(str, "restore", BU_LOG_RESTORE)
186 0 : || is_wrap(str, "verify", BU_LOG_VERIFY)
187 0 : || is_wrap(str, "backup_stats", BU_STATS_BACKUP)
188 0 : || is_wrap(str, "restore_stats", BU_STATS_RESTORE)
189 0 : || is_wrap(str, "verify_stats", BU_STATS_VERIFY))
190 : goto end;
191 : }
192 5 : else if(!strcmp(lastkey, "logs"))
193 : {
194 : goto end;
195 : }
196 5 : else if(!strcmp(lastkey, "logline"))
197 : {
198 : goto end;
199 : }
200 5 : else if(!strcmp(lastkey, "backup")
201 5 : || !strcmp(lastkey, "restore")
202 5 : || !strcmp(lastkey, "verify")
203 5 : || !strcmp(lastkey, "backup_stats")
204 5 : || !strcmp(lastkey, "restore_stats")
205 5 : || !strcmp(lastkey, "verify_stats"))
206 : {
207 : // Log file contents.
208 0 : if(lline_add(&ll_list, str))
209 : goto error;
210 : goto end;
211 : }
212 5 : else if(!strcmp(lastkey, "warning"))
213 : {
214 : goto end;
215 : }
216 : error:
217 0 : logp("Unexpected string: %s %s\n", lastkey, str);
218 0 : free_w(&str);
219 0 : return 0;
220 : end:
221 495 : free_w(&str);
222 495 : return 1;
223 : }
224 :
225 930 : static int input_map_key(void *ctx, const unsigned char *val, size_t len)
226 : {
227 930 : snprintf(lastkey, len+1, "%s", val);
228 : // logp("mapkey: %s\n", lastkey);
229 930 : return 1;
230 : }
231 :
232 : static struct bu *bu_list=NULL;
233 :
234 195 : static int add_to_bu_list(void)
235 : {
236 : struct bu *bu;
237 : struct bu *last;
238 195 : if(!number) return 0;
239 115 : if(!(bu=bu_alloc())) return -1;
240 115 : bu->bno=number;
241 115 : bu->flags=flags;
242 115 : bu->timestamp=timestamp;
243 :
244 : // FIX THIS: Inefficient to find the end each time.
245 115 : for(last=bu_list; last && last->next; last=last->next) { }
246 115 : if(last)
247 : {
248 50 : last->next=bu;
249 50 : bu->prev=last;
250 : }
251 : else
252 : {
253 65 : bu_list=bu;
254 65 : bu_list->prev=NULL;
255 : }
256 :
257 115 : number=0;
258 115 : flags=0;
259 115 : timestamp=NULL;
260 115 : return 0;
261 : }
262 :
263 298 : static int input_start_map(void *ctx)
264 : {
265 298 : map_depth++;
266 : //logp("startmap: %d\n", map_depth);
267 298 : return 1;
268 : }
269 :
270 297 : static int input_end_map(void *ctx)
271 : {
272 297 : map_depth--;
273 : //logp("endmap: %d\n", map_depth);
274 297 : if(in_backups && !in_flags && !in_counters && !in_logslist)
275 : {
276 115 : if(add_to_bu_list()) return 0;
277 : }
278 : return 1;
279 : }
280 :
281 275 : static int input_start_array(void *ctx)
282 : {
283 : //logp("start arr\n");
284 275 : if(!strcmp(lastkey, "backups"))
285 : {
286 80 : in_backups=1;
287 : }
288 195 : else if(!strcmp(lastkey, "flags"))
289 : {
290 115 : in_flags=1;
291 : }
292 80 : else if(!strcmp(lastkey, "counters"))
293 : {
294 30 : in_counters=1;
295 : }
296 50 : else if(!strcmp(lastkey, "list"))
297 : {
298 0 : in_logslist=1;
299 : }
300 50 : else if(!strcmp(lastkey, "backup")
301 50 : || !strcmp(lastkey, "restore")
302 50 : || !strcmp(lastkey, "verify")
303 50 : || !strcmp(lastkey, "backup_stats")
304 50 : || !strcmp(lastkey, "restore_stats")
305 50 : || !strcmp(lastkey, "verify_stats"))
306 : {
307 0 : in_log_content=1;
308 : }
309 275 : return 1;
310 : }
311 :
312 80 : static void merge_bu_lists(void)
313 : {
314 : struct bu *n;
315 : struct bu *o;
316 80 : struct bu *lastn=NULL;
317 80 : struct bu *lasto=NULL;
318 :
319 229 : for(o=current->bu; o; )
320 : {
321 69 : int found_in_new=0;
322 69 : lastn=NULL;
323 87 : for(n=bu_list; n; n=n->next)
324 : {
325 87 : if(o->bno==n->bno)
326 : {
327 : // Found o in new list.
328 : // Copy the fields from new to old.
329 69 : found_in_new=1;
330 69 : o->flags=n->flags;
331 69 : free_w(&o->timestamp);
332 69 : o->timestamp=n->timestamp;
333 69 : n->timestamp=NULL;
334 :
335 : // Remove it from new list.
336 69 : if(lastn)
337 : {
338 18 : lastn->next=n->next;
339 18 : if(n->next) n->next->prev=lastn;
340 : }
341 : else
342 : {
343 51 : bu_list=n->next;
344 51 : if(bu_list) bu_list->prev=NULL;
345 : }
346 69 : bu_free(&n);
347 69 : n=lastn;
348 69 : break;
349 : }
350 18 : lastn=n;
351 : }
352 69 : if(!found_in_new)
353 : {
354 : // Could not find o in new list.
355 : // Remove it from old list.
356 0 : if(lasto)
357 : {
358 0 : lasto->next=o->next;
359 0 : if(o->next) o->next->prev=lasto;
360 : }
361 : else
362 : {
363 0 : current->bu=o->next;
364 0 : if(current->bu) current->bu->prev=NULL;
365 : }
366 : // Need to reset if the one that was removed was
367 : // selected in ncurses.
368 0 : if(o==*sselbu) *sselbu=NULL;
369 0 : bu_free(&o);
370 0 : o=lasto;
371 : }
372 69 : lasto=o;
373 69 : if(o) o=o->next;
374 : }
375 :
376 : // Now, new list only has entries missing from old list.
377 80 : n=bu_list;
378 80 : lastn=NULL;
379 206 : while(n)
380 : {
381 46 : o=current->bu;
382 46 : lasto=NULL;
383 112 : while(o && n->bno < o->bno)
384 : {
385 20 : lasto=o;
386 20 : o=o->next;
387 : }
388 : // Found the place to insert it.
389 46 : if(lasto)
390 : {
391 8 : lasto->next=n;
392 8 : n->prev=lasto;
393 : }
394 : else
395 : {
396 38 : if(current->bu) current->bu->prev=n;
397 38 : current->bu=n;
398 38 : current->bu->prev=NULL;
399 : }
400 46 : lastn=n->next;
401 46 : n->next=o;
402 46 : n=lastn;
403 : }
404 80 : }
405 :
406 275 : static int input_end_array(void *ctx)
407 : {
408 275 : if(in_backups && !in_flags && !in_counters && !in_logslist)
409 : {
410 80 : in_backups=0;
411 80 : if(add_to_bu_list()) return 0;
412 : // Now may have two lists. Want to keep the old one is intact
413 : // as possible, so that we can keep a pointer to its entries
414 : // in the ncurses stuff.
415 : // Merge the new list into the old.
416 80 : merge_bu_lists();
417 80 : bu_list=NULL;
418 80 : if(cnew)
419 : {
420 32 : cstat_add_to_list(cslist, cnew);
421 32 : cnew=NULL;
422 : }
423 80 : current=NULL;
424 : }
425 195 : else if(in_flags)
426 : {
427 115 : in_flags=0;
428 : }
429 80 : else if(in_counters)
430 : {
431 30 : in_counters=0;
432 : }
433 50 : else if(in_logslist)
434 : {
435 0 : in_logslist=0;
436 : }
437 50 : else if(in_log_content)
438 : {
439 0 : in_log_content=0;
440 0 : llines_free(sllines);
441 0 : *sllines=ll_list;
442 0 : ll_list=NULL;
443 : }
444 : return 1;
445 : }
446 :
447 : static yajl_callbacks callbacks = {
448 : NULL,
449 : NULL,
450 : input_integer,
451 : NULL,
452 : NULL,
453 : input_string,
454 : input_start_map,
455 : input_map_key,
456 : input_end_map,
457 : input_start_array,
458 : input_end_array
459 : };
460 :
461 2 : static void do_yajl_error(yajl_handle yajl, struct asfd *asfd)
462 : {
463 : unsigned char *str;
464 : str=yajl_get_error(yajl, 1,
465 2 : (const unsigned char *)asfd->rbuf->buf, asfd->rbuf->len);
466 2 : logp("yajl error: %s\n", str?(const char *)str:"unknown");
467 2 : if(str) yajl_free_error(yajl, str);
468 2 : }
469 :
470 : static yajl_handle yajl=NULL;
471 :
472 45 : int json_input_init(void)
473 : {
474 45 : if(!(yajl=yajl_alloc(&callbacks, NULL, NULL)))
475 : return -1;
476 45 : yajl_config(yajl, yajl_dont_validate_strings, 1);
477 45 : return 0;
478 : }
479 :
480 22 : void json_input_free(void)
481 : {
482 88 : if(!yajl) return;
483 45 : yajl_free(yajl);
484 45 : yajl=NULL;
485 : }
486 :
487 : // Client records will be coming through in alphabetical order.
488 : // FIX THIS: If a client is deleted on the server, it is not deleted from
489 : // clist.
490 5283 : int json_input(struct asfd *asfd, struct sel *sel)
491 : {
492 5281 : cslist=&sel->clist;
493 5281 : sselbu=&sel->backup;
494 5281 : sllines=&sel->llines;
495 :
496 5281 : if(!yajl && json_input_init()) goto error;
497 :
498 5281 : if(yajl_parse(yajl, (const unsigned char *)asfd->rbuf->buf,
499 5281 : asfd->rbuf->len)!=yajl_status_ok)
500 : {
501 2 : do_yajl_error(yajl, asfd);
502 1 : goto error;
503 : }
504 :
505 5280 : if(!map_depth)
506 : {
507 : // Got to the end of the JSON object.
508 43 : if(!sel->gotfirstresponse) sel->gotfirstresponse=1;
509 43 : if(yajl_complete_parse(yajl)!=yajl_status_ok)
510 : {
511 2 : do_yajl_error(yajl, asfd);
512 1 : goto error;
513 : }
514 : json_input_free();
515 : return 1;
516 : }
517 :
518 : return 0;
519 : error:
520 : json_input_free();
521 : return -1;
522 : }
|