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