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