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