LCOV - code coverage report
Current view: top level - src/client/monitor - json_input.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 199 274 72.6 %
Date: 2017-05-30 Functions: 16 18 88.9 %

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

Generated by: LCOV version 1.10