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