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 899 : if(!strcmp(val, key))
41 : {
42 204 : flags|=bit;
43 : return 1;
44 : }
45 : return 0;
46 : }
47 :
48 406 : static int input_integer(void *ctx, long long val)
49 : {
50 406 : 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 346 : else if(in_backups && !in_flags && !in_counters && !in_logslist)
84 : {
85 254 : if(!current) goto error;
86 254 : if(!strcmp(lastkey, "number"))
87 : {
88 127 : number=(unsigned long)val;
89 127 : return 1;
90 : }
91 127 : else if(!strcmp(lastkey, "timestamp"))
92 : {
93 : time_t t;
94 127 : t=(unsigned long)val;
95 127 : free_w(×tamp);
96 127 : if(!(timestamp=strdup_w(getdatestr(t), __func__)))
97 : return 0;
98 127 : return 1;
99 : }
100 : }
101 : else
102 : {
103 92 : 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 543 : static int input_string(void *ctx, const unsigned char *val, size_t len)
114 : {
115 : char *str;
116 543 : if(!(str=(char *)malloc_w(len+2, __func__)))
117 : return 0;
118 543 : snprintf(str, len+1, "%s", val);
119 :
120 543 : 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 423 : else if(!strcmp(lastkey, "name"))
139 : {
140 92 : if(cnew) goto error;
141 92 : if(!(current=cstat_get_by_name(*cslist, str)))
142 : {
143 88 : if(!(cnew=cstat_alloc())
144 44 : || cstat_init_with_cntr(cnew, str, NULL))
145 : goto error;
146 44 : current=cnew;
147 : }
148 : goto end;
149 : }
150 331 : else if(!strcmp(lastkey, "labels"))
151 : {
152 30 : if(!current) goto error;
153 : goto end;
154 : }
155 301 : else if(!strcmp(lastkey, "run_status"))
156 : {
157 92 : if(!current) goto error;
158 92 : current->run_status=run_str_to_status(str);
159 92 : goto end;
160 : }
161 209 : 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 209 : else if(!strcmp(lastkey, "flags"))
168 : {
169 204 : if(!current) goto error;
170 408 : if(is_wrap(str, "hardlinked", BU_HARDLINKED)
171 398 : || is_wrap(str, "deletable", BU_DELETABLE)
172 324 : || is_wrap(str, "working", BU_WORKING)
173 294 : || is_wrap(str, "finishing", BU_FINISHING)
174 264 : || is_wrap(str, "current", BU_CURRENT)
175 314 : || 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 543 : free_w(&str);
222 543 : return 1;
223 : }
224 :
225 1018 : static int input_map_key(void *ctx, const unsigned char *val, size_t len)
226 : {
227 1018 : snprintf(lastkey, len+1, "%s", val);
228 : // logp("mapkey: %s\n", lastkey);
229 1018 : return 1;
230 : }
231 :
232 : static struct bu *bu_list=NULL;
233 :
234 219 : static int add_to_bu_list(void)
235 : {
236 : struct bu *bu;
237 : struct bu *last;
238 219 : if(!number) return 0;
239 127 : if(!(bu=bu_alloc())) return -1;
240 127 : bu->bno=number;
241 127 : bu->flags=flags;
242 127 : bu->timestamp=timestamp;
243 :
244 : // FIX THIS: Inefficient to find the end each time.
245 127 : for(last=bu_list; last && last->next; last=last->next) { }
246 127 : if(last)
247 : {
248 50 : last->next=bu;
249 50 : bu->prev=last;
250 : }
251 : else
252 : {
253 77 : bu_list=bu;
254 77 : bu_list->prev=NULL;
255 : }
256 :
257 127 : number=0;
258 127 : flags=0;
259 127 : timestamp=NULL;
260 127 : return 0;
261 : }
262 :
263 326 : static int input_start_map(void *ctx)
264 : {
265 326 : map_depth++;
266 : //logp("startmap: %d\n", map_depth);
267 326 : return 1;
268 : }
269 :
270 325 : static int input_end_map(void *ctx)
271 : {
272 325 : map_depth--;
273 : //logp("endmap: %d\n", map_depth);
274 325 : if(in_backups && !in_flags && !in_counters && !in_logslist)
275 : {
276 127 : if(add_to_bu_list()) return 0;
277 : }
278 : return 1;
279 : }
280 :
281 303 : static int input_start_array(void *ctx)
282 : {
283 : //logp("start arr\n");
284 303 : if(!strcmp(lastkey, "backups"))
285 : {
286 92 : in_backups=1;
287 : }
288 211 : else if(!strcmp(lastkey, "flags"))
289 : {
290 127 : in_flags=1;
291 : }
292 84 : else if(!strcmp(lastkey, "counters"))
293 : {
294 30 : in_counters=1;
295 : }
296 54 : else if(!strcmp(lastkey, "list"))
297 : {
298 0 : in_logslist=1;
299 : }
300 54 : else if(!strcmp(lastkey, "backup")
301 54 : || !strcmp(lastkey, "restore")
302 54 : || !strcmp(lastkey, "verify")
303 54 : || !strcmp(lastkey, "backup_stats")
304 54 : || !strcmp(lastkey, "restore_stats")
305 54 : || !strcmp(lastkey, "verify_stats"))
306 : {
307 0 : in_log_content=1;
308 : }
309 303 : return 1;
310 : }
311 :
312 92 : static void merge_bu_lists(void)
313 : {
314 : struct bu *n;
315 : struct bu *o;
316 92 : struct bu *lastn=NULL;
317 92 : struct bu *lasto=NULL;
318 :
319 253 : 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 92 : n=bu_list;
378 92 : lastn=NULL;
379 242 : while(n)
380 : {
381 58 : o=current->bu;
382 58 : lasto=NULL;
383 136 : 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 58 : if(lasto)
390 : {
391 8 : lasto->next=n;
392 8 : n->prev=lasto;
393 : }
394 : else
395 : {
396 50 : if(current->bu) current->bu->prev=n;
397 50 : current->bu=n;
398 50 : current->bu->prev=NULL;
399 : }
400 58 : lastn=n->next;
401 58 : n->next=o;
402 58 : n=lastn;
403 : }
404 92 : }
405 :
406 303 : static int input_end_array(void *ctx)
407 : {
408 303 : if(in_backups && !in_flags && !in_counters && !in_logslist)
409 : {
410 92 : in_backups=0;
411 92 : 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 92 : merge_bu_lists();
417 92 : bu_list=NULL;
418 92 : if(cnew)
419 : {
420 44 : cstat_add_to_list(cslist, cnew);
421 44 : cnew=NULL;
422 : }
423 92 : current=NULL;
424 : }
425 211 : else if(in_flags)
426 : {
427 127 : in_flags=0;
428 : }
429 84 : else if(in_counters)
430 : {
431 30 : in_counters=0;
432 : }
433 54 : else if(in_logslist)
434 : {
435 0 : in_logslist=0;
436 : }
437 54 : 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 53 : int json_input_init(void)
473 : {
474 53 : if(!(yajl=yajl_alloc(&callbacks, NULL, NULL)))
475 : return -1;
476 53 : yajl_config(yajl, yajl_dont_validate_strings, 1);
477 53 : return 0;
478 : }
479 :
480 30 : void json_input_free(void)
481 : {
482 108 : if(!yajl) return;
483 53 : yajl_free(yajl);
484 53 : 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 5287 : int json_input(struct asfd *asfd, struct sel *sel)
491 : {
492 5285 : cslist=&sel->clist;
493 5285 : sselbu=&sel->backup;
494 5285 : sllines=&sel->llines;
495 :
496 5285 : if(!yajl && json_input_init()) goto error;
497 :
498 5285 : if(yajl_parse(yajl, (const unsigned char *)asfd->rbuf->buf,
499 5285 : asfd->rbuf->len)!=yajl_status_ok)
500 : {
501 2 : do_yajl_error(yajl, asfd);
502 1 : goto error;
503 : }
504 :
505 5284 : if(!map_depth)
506 : {
507 : // Got to the end of the JSON object.
508 47 : if(yajl_complete_parse(yajl)!=yajl_status_ok)
509 : {
510 2 : do_yajl_error(yajl, asfd);
511 1 : goto error;
512 : }
513 : json_input_free();
514 : return 1;
515 : }
516 :
517 : return 0;
518 : error:
519 : json_input_free();
520 : return -1;
521 : }
|