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