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