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 "../../cmd.h"
7 : #include "../../cstat.h"
8 : #include "../../fzp.h"
9 : #include "../../handy.h"
10 : #include "../../iobuf.h"
11 : #include "../../prepend.h"
12 : #include "../../strlist.h"
13 : #include "../../yajl_gen_w.h"
14 : #include "../timestamp.h"
15 : #include "browse.h"
16 : #include "json_output.h"
17 :
18 : static int pretty_print=1;
19 : static long version_2_1_8=0;
20 :
21 8 : void json_set_pretty_print(int value)
22 : {
23 8 : pretty_print=value;
24 8 : }
25 :
26 8 : static int write_all(struct asfd *asfd)
27 : {
28 8 : int ret=-1;
29 8 : size_t w=0;
30 8 : size_t len=0;
31 : const unsigned char *buf;
32 : struct iobuf wbuf;
33 :
34 8 : yajl_gen_get_buf(yajl, &buf, &len);
35 24 : while(len)
36 : {
37 8 : w=len;
38 8 : if(w>ASYNC_BUF_LEN) w=ASYNC_BUF_LEN;
39 8 : iobuf_set(&wbuf, CMD_GEN /* not used */, (char *)buf, w);
40 8 : if((ret=asfd->write(asfd, &wbuf)))
41 : break;
42 8 : buf+=w;
43 8 : len-=w;
44 : }
45 8 : if(!ret && !pretty_print)
46 : {
47 0 : iobuf_set(&wbuf, CMD_GEN /* not used */, (char *)"\n", 1);
48 0 : ret=asfd->write(asfd, &wbuf);
49 : }
50 :
51 8 : yajl_gen_clear(yajl);
52 8 : return ret;
53 : }
54 :
55 8 : static int json_start(void)
56 : {
57 8 : if(!yajl)
58 : {
59 8 : if(!(yajl=yajl_gen_alloc(NULL)))
60 : return -1;
61 8 : yajl_gen_config(yajl, yajl_gen_beautify, pretty_print);
62 8 : if(!version_2_1_8)
63 8 : version_2_1_8=version_to_long("2.1.8");
64 : }
65 8 : if(yajl_map_open_w()) return -1;
66 8 : return 0;
67 : }
68 :
69 7 : static int json_clients(void)
70 : {
71 7 : if(yajl_gen_str_w("clients")
72 7 : || yajl_array_open_w())
73 : return -1;
74 : return 0;
75 : }
76 :
77 : static int json_clients_end(void)
78 : {
79 7 : if(yajl_array_close_w()) return -1;
80 : return 0;
81 : }
82 :
83 8 : static int json_end(struct asfd *asfd)
84 : {
85 8 : int ret=-1;
86 8 : if(yajl_map_close_w())
87 : goto end;
88 8 : ret=write_all(asfd);
89 : end:
90 8 : yajl_gen_free(yajl);
91 8 : yajl=NULL;
92 8 : return ret;
93 : }
94 :
95 : static int flag_matches(struct bu *bu, uint16_t flag)
96 : {
97 138 : return (bu && (bu->flags & flag));
98 : }
99 :
100 138 : static int flag_wrap_str(struct bu *bu, uint16_t flag, const char *field)
101 : {
102 276 : if(!flag_matches(bu, flag)) return 0;
103 36 : return yajl_gen_str_w(field);
104 : }
105 :
106 0 : static struct fzp *open_backup_log(struct bu *bu, const char *logfile)
107 : {
108 0 : char *path=NULL;
109 0 : struct fzp *fzp=NULL;
110 :
111 0 : char logfilereal[32]="";
112 0 : if(!strcmp(logfile, "backup"))
113 : snprintf(logfilereal, sizeof(logfilereal), "log");
114 0 : else if(!strcmp(logfile, "restore"))
115 : snprintf(logfilereal, sizeof(logfilereal), "restorelog");
116 0 : else if(!strcmp(logfile, "verify"))
117 : snprintf(logfilereal, sizeof(logfilereal), "verifylog");
118 0 : else if(!strcmp(logfile, "backup_stats"))
119 : snprintf(logfilereal, sizeof(logfilereal), "backup_stats");
120 0 : else if(!strcmp(logfile, "restore_stats"))
121 : snprintf(logfilereal, sizeof(logfilereal), "restore_stats");
122 0 : else if(!strcmp(logfile, "verify_stats"))
123 : snprintf(logfilereal, sizeof(logfilereal), "verify_stats");
124 :
125 0 : if(!(path=prepend_s(bu->path, logfilereal)))
126 : goto end;
127 0 : if(!(fzp=fzp_gzopen(path, "rb")))
128 : {
129 0 : if(astrcat(&path, ".gz", __func__)
130 0 : || !(fzp=fzp_gzopen(path, "rb")))
131 : goto end;
132 : }
133 : end:
134 0 : free_w(&path);
135 0 : return fzp;
136 :
137 : }
138 :
139 0 : static int flag_wrap_str_zp(struct bu *bu, uint16_t flag, const char *field,
140 : const char *logfile)
141 : {
142 0 : int ret=-1;
143 0 : struct fzp *fzp=NULL;
144 0 : if(!flag_matches(bu, flag)
145 0 : || !logfile || strcmp(logfile, field))
146 : return 0;
147 0 : if(!(fzp=open_backup_log(bu, logfile))) goto end;
148 0 : if(yajl_gen_str_w(field)) goto end;
149 0 : if(yajl_array_open_w()) goto end;
150 0 : if(fzp)
151 : {
152 0 : char *cp=NULL;
153 0 : char buf[1024]="";
154 0 : while(fzp_gets(fzp, buf, sizeof(buf)))
155 : {
156 0 : if((cp=strrchr(buf, '\n'))) *cp='\0';
157 0 : if(yajl_gen_str_w(buf))
158 : goto end;
159 : }
160 : }
161 0 : if(yajl_array_close_w()) goto end;
162 0 : ret=0;
163 : end:
164 0 : fzp_close(&fzp);
165 0 : return ret;
166 : }
167 :
168 0 : static int do_counters(struct cntr *cntr)
169 : {
170 : static char type[2];
171 : struct cntr_ent *e;
172 :
173 : #ifndef UTEST
174 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=(uint64_t)time(NULL);
175 : #endif
176 0 : if(yajl_gen_str_w("counters")
177 0 : || yajl_array_open_w()) return -1;
178 0 : for(e=cntr->list; e; e=e->next)
179 : {
180 0 : if(e->flags & CNTR_SINGLE_FIELD)
181 : {
182 0 : if(!e->count) continue;
183 0 : snprintf(type, sizeof(type), "%c", e->cmd);
184 0 : if(yajl_map_open_w()
185 0 : || yajl_gen_str_pair_w("name", e->field)
186 0 : || yajl_gen_str_pair_w("type", type)
187 0 : || yajl_gen_int_pair_w("count", e->count)
188 0 : || yajl_map_close_w())
189 : return -1;
190 : }
191 0 : else if(e->flags & CNTR_TABULATE)
192 : {
193 0 : if(!e->count
194 0 : && !e->changed
195 0 : && !e->same
196 0 : && !e->deleted
197 0 : && !e->phase1)
198 0 : continue;
199 0 : snprintf(type, sizeof(type), "%c", e->cmd);
200 0 : if(yajl_map_open_w()
201 0 : || yajl_gen_str_pair_w("name", e->field)
202 0 : || yajl_gen_str_pair_w("type", type)
203 0 : || yajl_gen_int_pair_w("count", e->count)
204 0 : || yajl_gen_int_pair_w("changed", e->changed)
205 0 : || yajl_gen_int_pair_w("same", e->same)
206 0 : || yajl_gen_int_pair_w("deleted", e->deleted)
207 0 : || yajl_gen_int_pair_w("scanned", e->phase1)
208 0 : || yajl_map_close_w())
209 : return -1;
210 : }
211 : }
212 :
213 0 : if(yajl_array_close_w())
214 : return -1;
215 : return 0;
216 : }
217 :
218 35 : static int json_send_backup(struct cstat *cstat, struct bu *bu,
219 : int print_flags, const char *logfile, const char *browse,
220 : int use_cache, long peer_version)
221 : {
222 35 : long long bno=0;
223 35 : long long timestamp=0;
224 35 : if(!bu) return 0;
225 23 : bno=(long long)bu->bno;
226 23 : timestamp=(long long)timestamp_to_long(bu->timestamp);
227 :
228 23 : if(yajl_map_open_w()
229 23 : || yajl_gen_int_pair_w("number", bno)
230 23 : || yajl_gen_int_pair_w("timestamp", timestamp)
231 23 : || yajl_gen_str_w("flags")
232 23 : || yajl_array_open_w()
233 23 : || flag_wrap_str(bu, BU_HARDLINKED, "hardlinked")
234 23 : || flag_wrap_str(bu, BU_DELETABLE, "deletable")
235 23 : || flag_wrap_str(bu, BU_WORKING, "working")
236 23 : || flag_wrap_str(bu, BU_FINISHING, "finishing")
237 23 : || flag_wrap_str(bu, BU_CURRENT, "current")
238 23 : || flag_wrap_str(bu, BU_MANIFEST, "manifest")
239 23 : || yajl_array_close_w())
240 : return -1;
241 23 : if(bu->flags & (BU_WORKING|BU_FINISHING))
242 : {
243 6 : if(peer_version<=version_2_1_8)
244 : {
245 0 : if(do_counters(cstat->cntrs))
246 : return -1;
247 : }
248 : }
249 23 : if(print_flags
250 23 : && (bu->flags & (BU_LOG_BACKUP|BU_LOG_RESTORE|BU_LOG_VERIFY
251 : |BU_STATS_BACKUP|BU_STATS_RESTORE|BU_STATS_VERIFY)))
252 : {
253 0 : if(yajl_gen_str_w("logs")
254 0 : || yajl_map_open_w()
255 0 : || yajl_gen_str_w("list")
256 0 : || yajl_array_open_w()
257 0 : || flag_wrap_str(bu, BU_LOG_BACKUP, "backup")
258 0 : || flag_wrap_str(bu, BU_LOG_RESTORE, "restore")
259 0 : || flag_wrap_str(bu, BU_LOG_VERIFY, "verify")
260 0 : || flag_wrap_str(bu, BU_STATS_BACKUP, "backup_stats")
261 0 : || flag_wrap_str(bu, BU_STATS_RESTORE, "restore_stats")
262 0 : || flag_wrap_str(bu, BU_STATS_VERIFY, "verify_stats")
263 0 : || yajl_array_close_w())
264 : return -1;
265 0 : if(logfile)
266 : {
267 0 : if(flag_wrap_str_zp(bu,
268 : BU_LOG_BACKUP, "backup", logfile)
269 0 : || flag_wrap_str_zp(bu,
270 : BU_LOG_RESTORE, "restore", logfile)
271 0 : || flag_wrap_str_zp(bu,
272 : BU_LOG_VERIFY, "verify", logfile)
273 0 : || flag_wrap_str_zp(bu,
274 : BU_STATS_BACKUP, "backup_stats", logfile)
275 0 : || flag_wrap_str_zp(bu,
276 : BU_STATS_RESTORE, "restore_stats", logfile)
277 0 : || flag_wrap_str_zp(bu,
278 : BU_STATS_VERIFY, "verify_stats", logfile))
279 : return -1;
280 : }
281 0 : if(yajl_map_close_w())
282 : return -1;
283 0 : if(browse)
284 : {
285 0 : if(yajl_gen_str_w("browse")) return -1;
286 0 : if(yajl_map_open_w()) return -1;
287 0 : if(yajl_gen_str_pair_w("directory", browse)) return -1;
288 0 : if(yajl_gen_str_w("entries")) return -1;
289 0 : if(yajl_array_open_w()) return -1;
290 0 : if(browse_manifest(cstat, bu, browse, use_cache))
291 : return -1;
292 0 : if(yajl_array_close_w()) return -1;
293 0 : if(yajl_map_close_w()) return -1;
294 :
295 : }
296 : }
297 23 : if(yajl_gen_map_close(yajl)!=yajl_gen_status_ok)
298 : return -1;
299 :
300 23 : return 0;
301 : }
302 :
303 16 : static int str_array(const char *field, struct cstat *cstat)
304 : {
305 16 : struct strlist *s=NULL;
306 16 : if(!cstat->labels) return 0;
307 3 : if(yajl_gen_str_w(field)
308 3 : || yajl_array_open_w())
309 : return -1;
310 9 : for(s=cstat->labels; s; s=s->next)
311 6 : if(yajl_gen_str_w(s->path))
312 : return -1;
313 3 : if(yajl_array_close_w())
314 : return -1;
315 : return 0;
316 : }
317 :
318 0 : static int do_children(struct cntr *cntrs)
319 : {
320 : struct cntr *c;
321 0 : if(yajl_gen_str_w("children")
322 0 : || yajl_array_open_w())
323 : return -1;
324 0 : for(c=cntrs; c; c=c->next)
325 : {
326 0 : if(yajl_map_open_w()
327 0 : || yajl_gen_int_pair_w("pid", c->pid)
328 0 : || yajl_gen_int_pair_w("backup", c->bno)
329 0 : || yajl_gen_str_pair_w("action", cntr_status_to_action_str(c))
330 0 : || yajl_gen_str_pair_w("phase", cntr_status_to_str(c)))
331 : return -1;
332 0 : if(do_counters(c))
333 : return -1;
334 0 : if(yajl_map_close_w())
335 : return -1;
336 : }
337 0 : if(yajl_array_close_w())
338 : return -1;
339 0 : return 0;
340 : }
341 :
342 16 : static int json_send_client_start(struct cstat *cstat, long peer_version)
343 : {
344 16 : const char *run_status=run_status_to_str(cstat);
345 :
346 16 : if(yajl_map_open_w()
347 16 : || yajl_gen_str_pair_w("name", cstat->name))
348 : return -1;
349 16 : if(str_array("labels", cstat))
350 : return -1;
351 16 : if(yajl_gen_str_pair_w("run_status", run_status))
352 : return -1;
353 16 : if(yajl_gen_int_pair_w("protocol", cstat->protocol))
354 : return -1;
355 16 : if(peer_version>version_2_1_8)
356 : {
357 16 : if(cstat->cntrs
358 0 : && do_children(cstat->cntrs))
359 : return -1;
360 : }
361 0 : else if(cstat->cntrs)
362 : {
363 : // Best effort.
364 0 : if(yajl_gen_str_pair_w("phase",
365 : cntr_status_to_str(cstat->cntrs)))
366 : return -1;
367 : }
368 16 : if(yajl_gen_str_w("backups")
369 16 : || yajl_array_open_w())
370 : return -1;
371 : return 0;
372 : }
373 :
374 16 : static int json_send_client_end(void)
375 : {
376 16 : if(yajl_array_close_w()
377 16 : || yajl_map_close_w())
378 : return -1;
379 : return 0;
380 : }
381 :
382 15 : static int json_send_client_backup(struct cstat *cstat, struct bu *bu1,
383 : struct bu *bu2, const char *logfile, const char *browse, int use_cache,
384 : long peer_version)
385 : {
386 15 : int ret=-1;
387 15 : if(json_send_client_start(cstat, peer_version))
388 : return -1;
389 15 : if((ret=json_send_backup(cstat, bu1,
390 : 1 /* print flags */, logfile, browse, use_cache, peer_version)))
391 : goto end;
392 15 : if((ret=json_send_backup(cstat, bu2,
393 : 1 /* print flags */, logfile, browse, use_cache, peer_version)))
394 : goto end;
395 : end:
396 15 : if(json_send_client_end()) ret=-1;
397 15 : return ret;
398 : }
399 :
400 1 : static int json_send_client_backup_list(struct cstat *cstat, int use_cache,
401 : long peer_version)
402 : {
403 1 : int ret=-1;
404 : struct bu *bu;
405 1 : if(json_send_client_start(cstat, peer_version))
406 : return -1;
407 6 : for(bu=cstat->bu; bu; bu=bu->prev)
408 : {
409 5 : if(json_send_backup(cstat, bu,
410 : 1 /* print flags */, NULL, NULL,
411 : use_cache, peer_version))
412 : goto end;
413 : }
414 : ret=0;
415 : end:
416 1 : if(json_send_client_end()) ret=-1;
417 1 : return ret;
418 : }
419 :
420 7 : int json_send(struct asfd *asfd, struct cstat *clist, struct cstat *cstat,
421 : struct bu *bu, const char *logfile, const char *browse,
422 : int use_cache, long peer_version)
423 : {
424 7 : int ret=-1;
425 : struct cstat *c;
426 :
427 7 : if(json_start()
428 7 : || json_clients())
429 : goto end;
430 :
431 7 : if(cstat && bu)
432 : {
433 0 : if(json_send_client_backup(cstat, bu, NULL,
434 : logfile, browse, use_cache, peer_version))
435 : goto end;
436 : }
437 7 : else if(cstat)
438 : {
439 1 : if(json_send_client_backup_list(cstat,
440 : use_cache, peer_version))
441 : goto end;
442 : }
443 15 : else for(c=clist; c; c=c->next)
444 : {
445 15 : if(!c->permitted) continue;
446 15 : if(json_send_client_backup(c,
447 : bu_find_current(c->bu),
448 : bu_find_working_or_finishing(c->bu),
449 : NULL, NULL, use_cache, peer_version))
450 : goto end;
451 : }
452 :
453 : ret=0;
454 : end:
455 7 : if(json_clients_end()
456 7 : || json_end(asfd)) return -1;
457 7 : return ret;
458 : }
459 :
460 0 : int json_cntr(struct asfd *asfd, struct cntr *cntr)
461 : {
462 0 : int ret=-1;
463 0 : if(json_start()
464 0 : || do_counters(cntr))
465 : goto end;
466 0 : ret=0;
467 : end:
468 0 : if(json_end(asfd)) return -1;
469 0 : return ret;
470 : }
471 :
472 0 : int json_from_entry(const char *path, const char *link, struct stat *statp)
473 : {
474 0 : return yajl_map_open_w()
475 0 : || yajl_gen_str_pair_w("name", path)
476 0 : || yajl_gen_str_pair_w("link", link? link:"")
477 0 : || yajl_gen_int_pair_w("dev", statp->st_dev)
478 0 : || yajl_gen_int_pair_w("ino", statp->st_ino)
479 0 : || yajl_gen_int_pair_w("mode", statp->st_mode)
480 0 : || yajl_gen_int_pair_w("nlink", statp->st_nlink)
481 0 : || yajl_gen_int_pair_w("uid", statp->st_uid)
482 0 : || yajl_gen_int_pair_w("gid", statp->st_gid)
483 0 : || yajl_gen_int_pair_w("rdev", statp->st_rdev)
484 0 : || yajl_gen_int_pair_w("size", statp->st_size)
485 0 : || yajl_gen_int_pair_w("blksize", statp->st_blksize)
486 0 : || yajl_gen_int_pair_w("blocks", statp->st_blocks)
487 0 : || yajl_gen_int_pair_w("atime", statp->st_atime)
488 0 : || yajl_gen_int_pair_w("ctime", statp->st_ctime)
489 0 : || yajl_gen_int_pair_w("mtime", statp->st_mtime)
490 0 : || yajl_map_close_w();
491 : }
492 :
493 1 : int json_send_warn(struct asfd *asfd, const char *msg)
494 : {
495 1 : if(json_start()
496 1 : || yajl_gen_str_pair_w("warning", msg)
497 1 : || json_end(asfd)) return -1;
498 : return 0;
499 : }
|