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