Line data Source code
1 : #include "../../burp.h"
2 : #include "../../action.h"
3 : #include "../../alloc.h"
4 : #include "../../asfd.h"
5 : #include "../../async.h"
6 : #include "../../bu.h"
7 : #include "../../cmd.h"
8 : #include "../../cstat.h"
9 : #include "../../forkchild.h"
10 : #include "../../fsops.h"
11 : #include "../../fzp.h"
12 : #include "../../handy.h"
13 : #include "../../iobuf.h"
14 : #include "../../log.h"
15 : #include "json_input.h"
16 : #include "lline.h"
17 : #include "sel.h"
18 : #include "status_client_ncurses.h"
19 :
20 : #ifdef HAVE_NCURSES_H
21 : #include "ncurses.h"
22 : // So that the sighandler can call endwin():
23 : static enum action actg=ACTION_STATUS;
24 : #endif
25 :
26 : #define LEFT_SPACE 3
27 : #define TOP_SPACE 2
28 :
29 : static struct fzp *lfzp=NULL;
30 :
31 : // For switching between seeing 'last backup' and counter summary on the front
32 : // screen.
33 : static uint8_t toggle=0;
34 :
35 0 : static void print_line(const char *string, int row, int col)
36 : {
37 0 : int k=0;
38 0 : const char *cp=NULL;
39 : #ifdef HAVE_NCURSES_H
40 0 : if(actg==ACTION_STATUS)
41 : {
42 0 : while(k<LEFT_SPACE) mvprintw(row+TOP_SPACE, k++, " ");
43 0 : for(cp=string; (*cp && k<col); cp++)
44 0 : mvprintw(row+TOP_SPACE, k++, "%c", *cp);
45 0 : while(k<col) mvprintw(row+TOP_SPACE, k++, " ");
46 0 : return;
47 : }
48 : #endif
49 0 : while(k<LEFT_SPACE) { printf(" "); k++; }
50 0 : for(cp=string; *cp; cp++)
51 : {
52 0 : printf("%c", *cp);
53 0 : k++;
54 : #ifdef HAVE_NCURSES_H
55 0 : if(actg==ACTION_STATUS && k<col) break;
56 : #endif
57 : }
58 0 : printf("\n");
59 : }
60 :
61 0 : static char *get_bu_str(struct bu *bu)
62 : {
63 : static char ret[32];
64 0 : if(!bu) snprintf(ret, sizeof(ret), "never");
65 0 : else if(!bu->bno) snprintf(ret, sizeof(ret), "%s", bu->timestamp);
66 0 : else snprintf(ret, sizeof(ret), "%07lu %s", bu->bno, bu->timestamp);
67 0 : return ret;
68 : }
69 :
70 0 : static void client_summary(struct cstat *cstat,
71 : int row, int col, int clientwidth, struct conf **confs)
72 : {
73 0 : char msg[1024]="";
74 0 : char fmt[64]="";
75 0 : struct bu *cbu=NULL;
76 : snprintf(fmt, sizeof(fmt), "%%-%d.%ds %%9s %%s%%s",
77 0 : clientwidth, clientwidth);
78 :
79 : // Find the current backup.
80 0 : cbu=bu_find_current(cstat->bu);
81 :
82 0 : switch(cstat->run_status)
83 : {
84 : case RUN_STATUS_RUNNING:
85 0 : if(toggle)
86 : {
87 0 : char f[64]="";
88 0 : char b[64]="";
89 0 : uint64_t p=0;
90 0 : uint64_t t=0;
91 0 : struct cntr *cntr=cstat->cntr;
92 : struct cntr_ent *ent_gtotal=
93 0 : cntr->ent[(uint8_t)CMD_GRAND_TOTAL];
94 :
95 : t=ent_gtotal->count
96 0 : +ent_gtotal->same
97 0 : +ent_gtotal->changed;
98 0 : if(ent_gtotal->phase1)
99 0 : p=(t*100)/ent_gtotal->phase1;
100 : snprintf(f, sizeof(f),
101 : " %"PRIu64"/%"PRIu64" %"PRIu64"%%",
102 0 : t, ent_gtotal->phase1, p);
103 0 : if(cntr->byte)
104 : snprintf(b, sizeof(b), "%s",
105 0 : bytes_to_human(cntr->byte));
106 : snprintf(msg, sizeof(msg), fmt,
107 : cstat->name,
108 : run_status_to_str(cstat),
109 0 : f, b);
110 0 : break;
111 : }
112 : // Else fall through.
113 : case RUN_STATUS_IDLE:
114 : case RUN_STATUS_SERVER_CRASHED:
115 : case RUN_STATUS_CLIENT_CRASHED:
116 : default:
117 : snprintf(msg, sizeof(msg), fmt,
118 : cstat->name,
119 : run_status_to_str(cstat),
120 : " last backup: ",
121 0 : get_bu_str(cbu));
122 0 : break;
123 : }
124 :
125 0 : if(*msg) print_line(msg, row, col);
126 0 : }
127 :
128 : /* for the counters */
129 0 : static void to_msg(char msg[], size_t s, const char *fmt, ...)
130 : {
131 : va_list ap;
132 0 : va_start(ap, fmt);
133 0 : vsnprintf(msg, s, fmt, ap);
134 0 : va_end(ap);
135 0 : }
136 :
137 0 : static void print_cntr_ent(const char *field,
138 : uint64_t a,
139 : uint64_t b,
140 : uint64_t c,
141 : uint64_t d,
142 : uint64_t e,
143 : int *x, int col)
144 : {
145 0 : char msg[256]="";
146 0 : uint64_t t=a+b+c;
147 0 : if(!field || (!t && !d && !e)) return;
148 :
149 : /* FIX THIS.
150 : if(phase==STATUS_RESTORING
151 : || phase==STATUS_VERIFYING)
152 : {
153 : to_msg(msg, sizeof(msg),
154 : "% 15s % 9s % 9llu % 9llu",
155 : field, "", t, e);
156 : }
157 : else
158 : {
159 : */
160 : to_msg(msg, sizeof(msg),
161 : "% 15s % 9llu % 9llu % 9llu % 9llu % 9llu % 9llu",
162 0 : field, a, b, c, d, t, e);
163 : // }
164 0 : print_line(msg, (*x)++, col);
165 : /* FIX THIS
166 : if(percent && e)
167 : {
168 : uint64_t p;
169 : p=(t*100)/e;
170 : if(phase==STATUS_RESTORING
171 : || phase==STATUS_VERIFYING)
172 : {
173 : to_msg(msg, sizeof(msg), "% 15s % 9s % 9llu%% % 9s",
174 : "", "", p, "");
175 : }
176 : else
177 : {
178 : to_msg(msg, sizeof(msg), "% 15s % 9s % 9s % 9s % 9s % 9llu%% % 9s",
179 : "", "", "", "", "", p, "");
180 : print_line(msg, (*x)++, col);
181 : }
182 : */
183 : }
184 :
185 0 : static void table_header(int *x, int col)
186 : {
187 0 : char msg[256]="";
188 : /* FIX THIS
189 : if(phase==STATUS_RESTORING
190 : || phase==STATUS_VERIFYING)
191 : {
192 : to_msg(msg, sizeof(msg), "% 15s % 9s % 9s % 9s",
193 : "", "", "Attempted", "Expected");
194 : }
195 : else
196 : {
197 : */
198 : to_msg(msg, sizeof(msg), "% 15s % 9s % 9s % 9s % 9s % 9s % 9s",
199 0 : "", "New", "Changed", "Unchanged", "Deleted", "Total", "Scanned");
200 : // }
201 0 : print_line(msg, (*x)++, col);
202 0 : }
203 :
204 : /*
205 : static void print_detail2(const char *field, uint64_t value1, const char *value2, int *x, int col)
206 : {
207 : char msg[256]="";
208 : if(!field || !value1 || !value2 || !*value2) return;
209 : snprintf(msg, sizeof(msg), "%s: %llu%s", field, value1, value2);
210 : print_line(msg, (*x)++, col);
211 : }
212 :
213 : static void print_detail3(const char *field, const char *value, int *x, int col)
214 : {
215 : char msg[256]="";
216 : if(!field || !value || !*value) return;
217 : snprintf(msg, sizeof(msg), "%s: %s", field, value);
218 : print_line(msg, (*x)++, col);
219 : }
220 : */
221 : /*
222 : static void detail(const char *cntrclient, char status, char phase, const char *path, struct cntr *p1cntr, struct cntr *cntr, struct strlist *backups, int row, int col)
223 : {
224 : int x=0;
225 : char msg[1024]="";
226 : print_line("", x++, col);
227 : table_header(phase, &x, col);
228 :
229 : print_detail(phase, "Files",
230 : cntr->file,
231 : cntr->file_changed,
232 : cntr->file_same,
233 : cntr->file_deleted,
234 : p1cntr->file,
235 : &x, col, 0);
236 : print_detail(phase, "Encrypted files",
237 : cntr->enc,
238 : cntr->enc_changed,
239 : cntr->enc_same,
240 : cntr->enc_deleted,
241 : p1cntr->enc,
242 : &x, col, 0);
243 : print_detail(phase, "Meta data",
244 : cntr->meta,
245 : cntr->meta_changed,
246 : cntr->meta_same,
247 : cntr->meta_deleted,
248 : p1cntr->meta,
249 : &x, col, 0);
250 : print_detail(phase, "Encrypted meta data",
251 : cntr->encmeta,
252 : cntr->encmeta_changed,
253 : cntr->encmeta_same,
254 : cntr->encmeta_deleted,
255 : p1cntr->encmeta,
256 : &x, col, 0);
257 : print_detail(phase, "Directories",
258 : cntr->dir,
259 : cntr->dir_changed,
260 : cntr->dir_same,
261 : cntr->dir_deleted,
262 : p1cntr->dir,
263 : &x, col, 0);
264 : print_detail(phase, "Soft links",
265 : cntr->slink,
266 : cntr->slink_changed,
267 : cntr->slink_same,
268 : cntr->slink_deleted,
269 : p1cntr->slink,
270 : &x, col, 0);
271 : print_detail(phase, "Hard links",
272 : cntr->hlink,
273 : cntr->hlink_changed,
274 : cntr->hlink_same,
275 : cntr->hlink_deleted,
276 : p1cntr->hlink,
277 : &x, col, 0);
278 : print_detail(phase, "Special files",
279 : cntr->special,
280 : cntr->special_changed,
281 : cntr->special_same,
282 : cntr->special_deleted,
283 : p1cntr->special,
284 : &x, col, 0);
285 : print_detail(phase, "Total",
286 : cntr->gtotal,
287 : cntr->gtotal_changed,
288 : cntr->gtotal_same,
289 : cntr->gtotal_deleted,
290 : p1cntr->gtotal,
291 : &x, col, 1);
292 : print_line("", x++, col);
293 : print_detail(phase, "Warnings",
294 : cntr->warning, 0, 0, 0, 0,
295 : &x, col, 1);
296 :
297 : if(p1cntr->byte)
298 : {
299 : tmp=bytes_to_human(p1cntr->byte);
300 : print_detail2("Bytes estimated", p1cntr->byte, tmp, &x, col);
301 : }
302 : if(cntr->byte)
303 : {
304 : const char *text=NULL;
305 : if(phase==STATUS_BACKUP) text="Bytes in backup";
306 : else if(phase==STATUS_RESTORING) text="Bytes attempted";
307 : else if(phase==STATUS_VERIFYING) text="Bytes checked";
308 : tmp=bytes_to_human(cntr->byte);
309 : if(text) print_detail2(text, cntr->byte, tmp, &x, col);
310 : }
311 : if(cntr->recvbyte)
312 : {
313 : const char *text=NULL;
314 : tmp=bytes_to_human(cntr->recvbyte);
315 : if(phase==STATUS_BACKUP) text="Bytes received";
316 : if(text) print_detail2(text, cntr->recvbyte, tmp, &x, col);
317 : }
318 : if(cntr->sentbyte)
319 : {
320 : const char *text=NULL;
321 : if(phase==STATUS_BACKUP) text="Bytes sent";
322 : else if(phase==STATUS_RESTORING) text="Bytes sent";
323 : tmp=bytes_to_human(cntr->sentbyte);
324 : print_detail2(text, cntr->sentbyte, tmp, &x, col);
325 : }
326 : if(p1cntr->start)
327 : {
328 : time_t now=0;
329 : time_t diff=0;
330 : now=time(NULL);
331 : diff=now-p1cntr->start;
332 :
333 : print_detail3("Start time", getdatestr(p1cntr->start), &x,col);
334 : print_detail3("Time taken", time_taken(diff), &x, col);
335 :
336 : if(diff>0)
337 : {
338 : uint64_t bytesleft=0;
339 : uint64_t byteswant=0;
340 : uint64_t bytesgot=0;
341 : float bytespersec=0;
342 : byteswant=p1cntr->byte;
343 : bytesgot=cntr->byte;
344 : bytespersec=(float)(bytesgot/diff);
345 : bytesleft=byteswant-bytesgot;
346 : if(bytespersec>0)
347 : {
348 : time_t timeleft=0;
349 : timeleft=(time_t)(bytesleft/bytespersec);
350 : print_detail3("Time left",
351 : time_taken(timeleft), &x, col);
352 : }
353 : }
354 : }
355 : if(path && *path)
356 : {
357 : #ifdef HAVE_NCURSES_H
358 : if(actg==ACTION_STATUS)
359 : {
360 : printw("\n%s\n", path);
361 : return;
362 : }
363 : #else
364 : printf("\n%s\n", path);
365 : #endif
366 : }
367 : }
368 : */
369 :
370 0 : static void screen_header(int row, int col)
371 : {
372 0 : int c=0;
373 0 : int l=0;
374 0 : const char *date=NULL;
375 0 : time_t t=time(NULL);
376 0 : date=getdatestr(t);
377 0 : l=strlen(date);
378 : #ifdef HAVE_NCURSES_H
379 0 : if(actg==ACTION_STATUS)
380 : {
381 0 : char v[32]="";
382 0 : snprintf(v, sizeof(v), " burp monitor %s", VERSION);
383 0 : print_line(v, 0-TOP_SPACE, col);
384 0 : mvprintw(0, col-l-1, date);
385 0 : return;
386 : }
387 : #endif
388 :
389 0 : printf("\n burp status");
390 :
391 0 : for(c=0; c<(int)(col-strlen(" burp status")-l-1); c++) printf(" ");
392 0 : printf("%s\n\n", date);
393 : }
394 :
395 0 : static int need_status(struct sel *sel)
396 : {
397 : static time_t lasttime=0;
398 0 : time_t now=0;
399 0 : time_t diff=0;
400 :
401 0 : if(sel->page==PAGE_VIEW_LOG && sel->llines) return 0;
402 :
403 : // Only ask for an update every second.
404 0 : now=time(NULL);
405 0 : diff=now-lasttime;
406 0 : if(diff<1)
407 : {
408 : // In case they fiddled their clock back in time.
409 0 : if(diff<0) lasttime=now;
410 0 : return 0;
411 : }
412 0 : lasttime=now;
413 0 : return 1;
414 : }
415 :
416 0 : static const char *logop_to_text(uint16_t logop)
417 : {
418 0 : switch(logop)
419 : {
420 0 : case BU_MANIFEST: return "Manifest";
421 0 : case BU_LOG_BACKUP: return "Backup log";
422 0 : case BU_LOG_RESTORE: return "Restore log";
423 0 : case BU_LOG_VERIFY: return "Verify log";
424 0 : case BU_STATS_BACKUP: return "Backup stats";
425 0 : case BU_STATS_RESTORE: return "Restore stats";
426 0 : case BU_STATS_VERIFY: return "Verify stats";
427 0 : default: return "";
428 : }
429 : }
430 :
431 0 : static void print_logs_list_line(struct sel *sel,
432 : uint16_t bit, int *x, int col)
433 : {
434 0 : char msg[64]="";
435 0 : if(!sel->backup || !(sel->backup->flags & bit)) return;
436 : snprintf(msg, sizeof(msg), "%s%s",
437 0 : *x==3?"Browse: ":" ", logop_to_text(bit));
438 0 : print_line(msg, (*x)++, col);
439 :
440 0 : if(!sel->logop) sel->logop=bit;
441 : #ifdef HAVE_NCURSES_H
442 0 : if(sel->logop==bit) mvprintw(*x+TOP_SPACE-1, 1, "*");
443 : #endif
444 : }
445 :
446 0 : static void client_and_status(struct sel *sel, int *x, int col)
447 : {
448 : char msg[1024];
449 0 : snprintf(msg, sizeof(msg), "Client: %s", sel->client->name);
450 : // sel->client->cntr->ent[CMD_FILE]->phase1,
451 : // sel->client->cntr->ent[CMD_FILE]->count);
452 0 : print_line(msg, (*x)++, col);
453 : snprintf(msg, sizeof(msg),
454 0 : "Status: %s", run_status_to_str(sel->client));
455 0 : print_line(msg, (*x)++, col);
456 0 : }
457 :
458 0 : static void client_and_status_and_backup(struct sel *sel, int *x, int col)
459 : {
460 : char msg[1024];
461 0 : client_and_status(sel, x, col);
462 0 : snprintf(msg, sizeof(msg), "Backup: %s", get_bu_str(sel->backup));
463 0 : print_line(msg, (*x)++, col);
464 0 : }
465 :
466 0 : static void client_and_status_and_backup_and_log(struct sel *sel,
467 : int *x, int col)
468 : {
469 : char msg[1024];
470 0 : client_and_status_and_backup(sel, x, col);
471 0 : snprintf(msg, sizeof(msg), "Browse: %s", logop_to_text(sel->logop));
472 0 : print_line(msg, (*x)++, col);
473 0 : }
474 :
475 : #ifdef HAVE_NCURSES_H
476 0 : static int selindex_from_cstat(struct sel *sel)
477 : {
478 0 : int selindex=0;
479 : struct cstat *c;
480 0 : for(c=sel->clist; c; c=c->next)
481 : {
482 0 : selindex++;
483 0 : if(sel->client==c) break;
484 : }
485 0 : return selindex;
486 : }
487 :
488 0 : static int selindex_from_bu(struct sel *sel)
489 : {
490 0 : int selindex=0;
491 : struct bu *b;
492 0 : for(b=sel->client->bu; b; b=b->next)
493 : {
494 0 : selindex++;
495 0 : if(sel->backup==b) break;
496 : }
497 0 : return selindex;
498 : }
499 :
500 0 : static int selindex_from_lline(struct sel *sel)
501 : {
502 0 : int selindex=0;
503 : struct lline *l;
504 0 : for(l=sel->llines; l; l=l->next)
505 : {
506 0 : selindex++;
507 0 : if(sel->lline==l) break;
508 : }
509 0 : return selindex;
510 : }
511 : #endif
512 :
513 0 : static void print_logs_list(struct sel *sel, int *x, int col)
514 : {
515 0 : print_logs_list_line(sel, BU_MANIFEST, x, col);
516 0 : print_logs_list_line(sel, BU_LOG_BACKUP, x, col);
517 0 : print_logs_list_line(sel, BU_LOG_RESTORE, x, col);
518 0 : print_logs_list_line(sel, BU_LOG_VERIFY, x, col);
519 0 : print_logs_list_line(sel, BU_STATS_BACKUP, x, col);
520 0 : print_logs_list_line(sel, BU_STATS_RESTORE, x, col);
521 0 : print_logs_list_line(sel, BU_STATS_VERIFY, x, col);
522 0 : }
523 :
524 0 : static void update_screen_clients(struct sel *sel, int *x, int col,
525 : int winmin, int winmax, struct conf **confs)
526 : {
527 : #ifdef HAVE_NCURSES_H
528 0 : int s=0;
529 : #endif
530 : struct cstat *c;
531 0 : int star_printed=0;
532 0 : int max_cname=28*((float)col/100);
533 : #ifdef HAVE_NCURSES_H
534 0 : if(actg==ACTION_STATUS_SNAPSHOT)
535 : #endif
536 : {
537 : size_t l;
538 0 : for(c=sel->clist; c; c=c->next)
539 0 : if((l=strlen(c->name))>(unsigned int)max_cname)
540 0 : max_cname=l;
541 : }
542 0 : for(c=sel->clist; c; c=c->next)
543 : {
544 : #ifdef HAVE_NCURSES_H
545 0 : if(actg==ACTION_STATUS)
546 : {
547 0 : s++;
548 0 : if(s<winmin) continue;
549 0 : if(s>winmax) break;
550 : }
551 : #endif
552 :
553 0 : client_summary(c, (*x)++, col, max_cname, confs);
554 :
555 : #ifdef HAVE_NCURSES_H
556 0 : if(actg==ACTION_STATUS && sel->client==c)
557 : {
558 0 : mvprintw((*x)+TOP_SPACE-1, 1, "*");
559 0 : star_printed=1;
560 : }
561 : #endif
562 : }
563 0 : if(!star_printed) sel->client=sel->clist;
564 0 : }
565 :
566 0 : static void update_screen_backups(struct sel *sel, int *x, int col,
567 : int winmin, int winmax)
568 : {
569 : #ifdef HAVE_NCURSES_H
570 0 : int s=0;
571 : #endif
572 : struct bu *b;
573 0 : char msg[1024]="";
574 0 : int star_printed=0;
575 0 : const char *extradesc=NULL;
576 0 : for(b=sel->client->bu; b; b=b->next)
577 : {
578 : #ifdef HAVE_NCURSES_H
579 0 : if(actg==ACTION_STATUS)
580 : {
581 0 : s++;
582 0 : if(s<winmin) continue;
583 0 : if(s>winmax) break;
584 : }
585 : #endif
586 :
587 0 : if(b->flags & BU_CURRENT)
588 0 : extradesc=" (current)";
589 0 : else if(b->flags & BU_WORKING)
590 0 : extradesc=" (working)";
591 0 : else if(b->flags & BU_FINISHING)
592 0 : extradesc=" (finishing)";
593 0 : else extradesc="";
594 :
595 : snprintf(msg, sizeof(msg), "%s %s%s",
596 0 : b==sel->client->bu?"Backup list:":
597 : " ",
598 : get_bu_str(b),
599 0 : extradesc);
600 0 : print_line(msg, (*x)++, col);
601 : #ifdef HAVE_NCURSES_H
602 0 : if(actg==ACTION_STATUS && sel->backup==b)
603 : {
604 0 : mvprintw((*x)+TOP_SPACE-1, 1, "*");
605 0 : star_printed=1;
606 : }
607 : #endif
608 : }
609 0 : if(!star_printed) sel->backup=sel->client->bu;
610 0 : }
611 :
612 0 : static void update_screen_live_counter_table(struct cntr_ent *e,
613 : int *x, int col)
614 : {
615 0 : if(!(e->flags & CNTR_TABULATE)) return;
616 : print_cntr_ent(e->label,
617 : e->count,
618 : e->changed,
619 : e->same,
620 : e->deleted,
621 : e->phase1,
622 0 : x, col);
623 : }
624 :
625 0 : static void update_screen_live_counter_single(struct cntr_ent *e,
626 : int *x, int col)
627 : {
628 0 : char msg[128]="";
629 0 : const char *bytes_human="";
630 0 : if(!(e->flags & CNTR_SINGLE_FIELD)) return;
631 0 : if(!e->count) return;
632 0 : switch(e->cmd)
633 : {
634 : case CMD_TIMESTAMP:
635 : case CMD_TIMESTAMP_END:
636 0 : return;
637 : case CMD_BYTES_ESTIMATED:
638 : case CMD_BYTES:
639 : case CMD_BYTES_RECV:
640 : case CMD_BYTES_SENT:
641 0 : bytes_human=bytes_to_human(e->count);
642 0 : break;
643 : default:
644 0 : break;
645 : }
646 : snprintf(msg, sizeof(msg), "%19s: %12"PRIu64" %s",
647 0 : e->label, e->count, bytes_human);
648 0 : print_line(msg, (*x)++, col);
649 : }
650 :
651 0 : static void update_screen_live_counters(struct cstat *client, int *x, int col)
652 : {
653 0 : char msg[128]="";
654 : struct cntr_ent *e;
655 0 : struct cntr *cntr=client->cntr;
656 0 : time_t start=(time_t)cntr->ent[(uint8_t)CMD_TIMESTAMP]->count;
657 0 : time_t end=(time_t)cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count;
658 0 : struct cntr_ent *gtotal=cntr->ent[(uint8_t)CMD_GRAND_TOTAL];
659 :
660 0 : print_line("", (*x)++, col);
661 0 : snprintf(msg, sizeof(msg), "Start time: %s", getdatestr(start));
662 0 : print_line(msg, (*x)++, col);
663 0 : snprintf(msg, sizeof(msg), " End time: %s", getdatestr(end));
664 0 : print_line(msg, (*x)++, col);
665 0 : snprintf(msg, sizeof(msg), "Time taken: %s", time_taken(end-start));
666 0 : print_line(msg, (*x)++, col);
667 0 : table_header(x, col);
668 0 : for(e=client->cntr->list; e; e=e->next)
669 0 : update_screen_live_counter_table(e, x, col);
670 0 : print_line("", (*x)++, col);
671 : snprintf(msg, sizeof(msg), "%19s: %"PRIu64"%%", "Percentage complete",
672 0 : ((gtotal->count+gtotal->same+gtotal->changed)*100)/gtotal->phase1);
673 0 : print_line(msg, (*x)++, col);
674 0 : print_line("", (*x)++, col);
675 0 : for(e=client->cntr->list; e; e=e->next)
676 0 : update_screen_live_counter_single(e, x, col);
677 0 : }
678 :
679 0 : static void update_screen_view_log(struct sel *sel, int *x, int col,
680 : int winmin, int winmax)
681 : {
682 : #ifdef HAVE_NCURSES_H
683 0 : int s=0;
684 : #endif
685 0 : int o=0;
686 : struct lline *l;
687 0 : const char *cp=NULL;
688 0 : int star_printed=0;
689 :
690 0 : if(sel->client
691 0 : && sel->backup
692 0 : && (sel->backup->flags & (BU_WORKING|BU_FINISHING))
693 0 : && (sel->logop & BU_STATS_BACKUP))
694 0 : return update_screen_live_counters(sel->client, x, col);
695 :
696 0 : for(l=sel->llines; l; l=l->next)
697 : {
698 : #ifdef HAVE_NCURSES_H
699 0 : if(actg==ACTION_STATUS)
700 : {
701 0 : s++;
702 0 : if(s<winmin) continue;
703 0 : if(s>winmax) break;
704 : }
705 : #endif
706 :
707 : // Allow them to scroll log lines left and right.
708 0 : for(cp=l->line, o=0; *cp && o<sel->offset; cp++, o++) { }
709 0 : print_line(cp, (*x)++, col);
710 :
711 : #ifdef HAVE_NCURSES_H
712 0 : if(actg==ACTION_STATUS && sel->lline==l)
713 : {
714 0 : mvprintw((*x)+TOP_SPACE-1, 1, "*");
715 0 : star_printed=1;
716 : }
717 : #endif
718 : }
719 0 : if(!star_printed) sel->lline=sel->llines;
720 : }
721 :
722 0 : static int update_screen(struct sel *sel, struct conf **confs)
723 : {
724 0 : int x=0;
725 0 : int row=24;
726 0 : int col=80;
727 : #ifdef HAVE_NCURSES_H
728 0 : int selindex=0;
729 : static int selindex_last=0;
730 : #endif
731 : static int winmin=0;
732 : static int winmax=0;
733 :
734 0 : screen_header(row, col);
735 :
736 : #ifdef HAVE_NCURSES_H
737 0 : if(actg==ACTION_STATUS)
738 : {
739 0 : getmaxyx(stdscr, row, col);
740 : //if(!winmax) winmax=row;
741 0 : switch(sel->page)
742 : {
743 : case PAGE_CLIENT_LIST:
744 0 : selindex=selindex_from_cstat(sel);
745 0 : break;
746 : case PAGE_BACKUP_LIST:
747 0 : selindex=selindex_from_bu(sel);
748 0 : break;
749 : case PAGE_BACKUP_LOGS:
750 0 : break;
751 : case PAGE_VIEW_LOG:
752 0 : selindex=selindex_from_lline(sel);
753 0 : break;
754 : }
755 : }
756 : #endif
757 0 : switch(sel->page)
758 : {
759 : case PAGE_CLIENT_LIST:
760 0 : break;
761 : case PAGE_BACKUP_LIST:
762 0 : client_and_status(sel, &x, col);
763 0 : break;
764 : case PAGE_BACKUP_LOGS:
765 0 : client_and_status_and_backup(sel, &x, col);
766 0 : break;
767 : case PAGE_VIEW_LOG:
768 0 : client_and_status_and_backup_and_log(sel, &x, col);
769 0 : break;
770 : }
771 :
772 : #ifdef HAVE_NCURSES_H
773 0 : if(actg==ACTION_STATUS)
774 : {
775 : // Adjust sliding window appropriately.
776 0 : if(selindex>selindex_last)
777 : {
778 0 : if(selindex>winmax-TOP_SPACE-1-x)
779 : {
780 0 : winmin+=selindex-selindex_last;
781 0 : winmax+=selindex-selindex_last;
782 : }
783 : }
784 0 : else if(selindex<selindex_last)
785 : {
786 0 : if(selindex<winmin)
787 : {
788 0 : winmin+=selindex-selindex_last;
789 0 : winmax+=selindex-selindex_last;
790 : }
791 : }
792 :
793 0 : if(winmin==winmax)
794 : {
795 0 : winmin=0;
796 0 : winmax=row;
797 : }
798 0 : else if(winmin<0)
799 : {
800 0 : winmin=0;
801 0 : winmax=row;
802 : }
803 : /*
804 : {
805 : char msg[64];
806 : snprintf(msg, sizeof(msg),
807 : "sel:%d si:%d min:%d max:%d %s\n",
808 : selindex, selindex_last, winmin, winmax,
809 : (selbu && *selbu && (*selbu)->prev)?
810 : (*selbu)->prev->timestamp:"");
811 : print_line(msg, -1, col);
812 : }
813 : */
814 : }
815 : #endif
816 :
817 0 : switch(sel->page)
818 : {
819 : case PAGE_CLIENT_LIST:
820 : update_screen_clients(sel, &x, col,
821 0 : winmin, winmax, confs);
822 0 : break;
823 : case PAGE_BACKUP_LIST:
824 : update_screen_backups(sel, &x, col,
825 0 : winmin, winmax);
826 0 : break;
827 : case PAGE_BACKUP_LOGS:
828 0 : print_logs_list(sel, &x, col);
829 0 : break;
830 : case PAGE_VIEW_LOG:
831 : update_screen_view_log(sel, &x, col,
832 0 : winmin, winmax);
833 0 : break;
834 : }
835 :
836 : #ifdef HAVE_NCURSES_H
837 0 : if(actg==ACTION_STATUS)
838 : {
839 : // Blank any remainder of the screen.
840 0 : for(; x<row; x++)
841 0 : print_line("", x, col);
842 0 : selindex_last=selindex;
843 : }
844 : #endif
845 0 : return 0;
846 : }
847 :
848 0 : static int request_status(struct asfd *asfd,
849 : const char *client, struct sel *sel, struct conf **confs)
850 : {
851 0 : char buf[256]="";
852 0 : switch(sel->page)
853 : {
854 : case PAGE_CLIENT_LIST:
855 0 : snprintf(buf, sizeof(buf), "c:\n");
856 0 : break;
857 : case PAGE_BACKUP_LIST:
858 0 : snprintf(buf, sizeof(buf), "c:%s\n", client);
859 0 : break;
860 : case PAGE_BACKUP_LOGS:
861 0 : if(sel->backup)
862 : snprintf(buf, sizeof(buf), "c:%s:b:%lu\n",
863 0 : client, sel->backup->bno);
864 0 : break;
865 : case PAGE_VIEW_LOG:
866 : {
867 0 : const char *lname=NULL;
868 0 : if(sel->logop & BU_LOG_BACKUP)
869 0 : lname="backup";
870 0 : else if(sel->logop & BU_LOG_RESTORE)
871 0 : lname="restore";
872 0 : else if(sel->logop & BU_LOG_VERIFY)
873 0 : lname="verify";
874 0 : else if(sel->logop & BU_MANIFEST)
875 0 : lname="manifest";
876 0 : else if(sel->logop & BU_STATS_BACKUP)
877 : {
878 : // Hack so that it does not request the logs for live
879 : // counters.
880 : // FIX THIS: need to do something similar for
881 : // restore/verify.
882 0 : if(!sel->backup) break;
883 0 : if(sel->client
884 0 : && sel->client->run_status==RUN_STATUS_RUNNING
885 0 : && sel->backup->flags
886 0 : & (BU_WORKING|BU_FINISHING))
887 : {
888 : // Make sure a request is sent, so that
889 : // the counters update.
890 : snprintf(buf, sizeof(buf),
891 : "c:%s:b:%lu\n",
892 0 : client, sel->backup->bno);
893 0 : break;
894 : }
895 : else
896 0 : lname="backup_stats";
897 : }
898 0 : else if(sel->logop & BU_STATS_RESTORE)
899 0 : lname="restore_stats";
900 0 : else if(sel->logop & BU_STATS_VERIFY)
901 0 : lname="verify_stats";
902 :
903 0 : if(sel->backup && lname)
904 : snprintf(buf, sizeof(buf), "c:%s:b:%lu:l:%s\n",
905 0 : client, sel->backup->bno, lname);
906 0 : break;
907 : }
908 : }
909 : /*
910 : if(confs->browsedir)
911 : snprintf(buf, sizeof(buf), "c:%s:b:%s:p:%s\n",
912 : client, confs->backup, confs->browsedir);
913 : else if(confs->browsefile)
914 : snprintf(buf, sizeof(buf), "c:%s:b:%s:f:%s\n",
915 : client, confs->backup, confs->browsefile);
916 : */
917 0 : if(*buf)
918 : {
919 0 : if(lfzp) logp("request: %s\n", buf);
920 0 : if(asfd->write_str(asfd, CMD_GEN /* ignored */, buf)) return -1;
921 : }
922 0 : return 0;
923 : }
924 :
925 0 : static void sighandler(int sig)
926 : {
927 : #ifdef HAVE_NCURSES_H
928 0 : if(actg==ACTION_STATUS) endwin();
929 : #endif
930 0 : logp("got signal: %d\n", sig);
931 0 : if(sig==SIGPIPE) logp("Server may have too many active status clients.\n");
932 0 : logp("exiting\n");
933 0 : exit(1);
934 : }
935 :
936 0 : static void setup_signals(void)
937 : {
938 0 : signal(SIGABRT, &sighandler);
939 0 : signal(SIGTERM, &sighandler);
940 0 : signal(SIGINT, &sighandler);
941 0 : signal(SIGPIPE, &sighandler);
942 0 : }
943 :
944 : #ifdef HAVE_NCURSES_H
945 0 : static void left(struct sel *sel)
946 : {
947 0 : switch(sel->page)
948 : {
949 : case PAGE_CLIENT_LIST:
950 0 : break;
951 : case PAGE_BACKUP_LIST:
952 0 : sel->page=PAGE_CLIENT_LIST;
953 0 : break;
954 : case PAGE_BACKUP_LOGS:
955 0 : sel->page=PAGE_BACKUP_LIST;
956 0 : break;
957 : case PAGE_VIEW_LOG:
958 0 : if(sel->offset>0)
959 : {
960 : // Allow log lines to be scrolled left.
961 0 : sel->offset--;
962 0 : break;
963 : }
964 0 : sel->page=PAGE_BACKUP_LOGS;
965 0 : llines_free(&sel->llines);
966 0 : sel->lline=NULL;
967 0 : break;
968 : }
969 0 : }
970 :
971 0 : static void right(struct sel *sel)
972 : {
973 0 : switch(sel->page)
974 : {
975 : case PAGE_CLIENT_LIST:
976 0 : sel->page=PAGE_BACKUP_LIST;
977 0 : break;
978 : case PAGE_BACKUP_LIST:
979 0 : sel->page=PAGE_BACKUP_LOGS;
980 0 : break;
981 : case PAGE_BACKUP_LOGS:
982 0 : if(lfzp) logp("Option selected: 0x%04X\n", sel->logop);
983 0 : sel->page=PAGE_VIEW_LOG;
984 0 : break;
985 : case PAGE_VIEW_LOG:
986 : // Allow log lines to be scrolled right.
987 0 : sel->offset++;
988 0 : break;
989 : }
990 0 : }
991 :
992 0 : static void up_client(struct sel *sel)
993 : {
994 0 : if(sel->client && sel->client->prev) sel->client=sel->client->prev;
995 0 : }
996 :
997 0 : static void down_client(struct sel *sel)
998 : {
999 0 : if(sel->client && sel->client->next) sel->client=sel->client->next;
1000 0 : }
1001 :
1002 0 : static void up_backup(struct sel *sel)
1003 : {
1004 0 : if(sel->backup && sel->backup->prev) sel->backup=sel->backup->prev;
1005 0 : }
1006 :
1007 0 : static void down_backup(struct sel *sel)
1008 : {
1009 0 : if(sel->backup && sel->backup->next) sel->backup=sel->backup->next;
1010 0 : }
1011 :
1012 0 : static void up_logs(struct sel *sel)
1013 : {
1014 0 : int i=0;
1015 0 : uint16_t sh=sel->logop;
1016 0 : for(i=0; sh>BU_MANIFEST && i<16; i++)
1017 : {
1018 0 : sh=sh>>1;
1019 0 : if(sh & sel->backup->flags)
1020 : {
1021 0 : sel->logop=sh;
1022 0 : break;
1023 : }
1024 : }
1025 0 : }
1026 :
1027 0 : static void down_logs(struct sel *sel)
1028 : {
1029 0 : int i=0;
1030 0 : uint16_t sh=sel->logop;
1031 0 : for(i=0; sh && i<16; i++)
1032 : {
1033 0 : sh=sh<<1;
1034 0 : if(sh & sel->backup->flags)
1035 : {
1036 0 : sel->logop=sh;
1037 0 : break;
1038 : }
1039 : }
1040 0 : }
1041 :
1042 0 : static void up_view_log(struct sel *sel)
1043 : {
1044 0 : if(sel->lline && sel->lline->prev) sel->lline=sel->lline->prev;
1045 0 : }
1046 :
1047 0 : static void down_view_log(struct sel *sel)
1048 : {
1049 0 : if(sel->lline && sel->lline->next) sel->lline=sel->lline->next;
1050 0 : }
1051 :
1052 0 : static void up(struct sel *sel)
1053 : {
1054 0 : switch(sel->page)
1055 : {
1056 : case PAGE_CLIENT_LIST:
1057 0 : up_client(sel);
1058 0 : break;
1059 : case PAGE_BACKUP_LIST:
1060 0 : up_backup(sel);
1061 0 : break;
1062 : case PAGE_BACKUP_LOGS:
1063 0 : up_logs(sel);
1064 0 : break;
1065 : case PAGE_VIEW_LOG:
1066 0 : up_view_log(sel);
1067 0 : break;
1068 : }
1069 0 : }
1070 :
1071 0 : static void down(struct sel *sel)
1072 : {
1073 0 : switch(sel->page)
1074 : {
1075 : case PAGE_CLIENT_LIST:
1076 0 : down_client(sel);
1077 0 : break;
1078 : case PAGE_BACKUP_LIST:
1079 0 : down_backup(sel);
1080 0 : break;
1081 : case PAGE_BACKUP_LOGS:
1082 0 : down_logs(sel);
1083 0 : break;
1084 : case PAGE_VIEW_LOG:
1085 0 : down_view_log(sel);
1086 0 : break;
1087 : }
1088 0 : }
1089 :
1090 0 : static void page_up_client(struct sel *sel, int row)
1091 : {
1092 : struct cstat *c;
1093 0 : for(c=sel->client; c; c=c->prev)
1094 : {
1095 0 : row--;
1096 0 : if(!row) break;
1097 : }
1098 0 : sel->client=c;
1099 0 : }
1100 :
1101 0 : static void page_down_client(struct sel *sel, int row)
1102 : {
1103 : struct cstat *c;
1104 0 : for(c=sel->client; c; c=c->next)
1105 : {
1106 0 : row--;
1107 0 : if(!row) break;
1108 0 : if(!c->next) break;
1109 : }
1110 0 : sel->client=c;
1111 0 : }
1112 :
1113 0 : static void page_up_backup(struct sel *sel, int row)
1114 : {
1115 : struct bu *b;
1116 0 : for(b=sel->backup; b; b=b->prev)
1117 : {
1118 0 : row--;
1119 0 : if(!row) break;
1120 : }
1121 0 : sel->backup=b;
1122 0 : }
1123 :
1124 0 : static void page_down_backup(struct sel *sel, int row)
1125 : {
1126 : struct bu *b;
1127 0 : for(b=sel->backup; b; b=b->next)
1128 : {
1129 0 : row--;
1130 0 : if(!row) break;
1131 0 : if(!b->next) break;
1132 : }
1133 0 : sel->backup=b;
1134 0 : }
1135 :
1136 0 : static void page_up(struct sel *sel)
1137 : {
1138 0 : int row=0;
1139 0 : int col=0;
1140 0 : getmaxyx(stdscr, row, col);
1141 0 : switch(sel->page)
1142 : {
1143 : case PAGE_CLIENT_LIST:
1144 0 : page_up_client(sel, row);
1145 0 : break;
1146 : case PAGE_BACKUP_LIST:
1147 0 : page_up_backup(sel, row);
1148 0 : break;
1149 : case PAGE_BACKUP_LOGS:
1150 0 : break;
1151 : case PAGE_VIEW_LOG:
1152 0 : break;
1153 : }
1154 0 : }
1155 :
1156 0 : static void page_down(struct sel *sel)
1157 : {
1158 0 : int row=0;
1159 0 : int col=0;
1160 0 : getmaxyx(stdscr, row, col);
1161 0 : switch(sel->page)
1162 : {
1163 : case PAGE_CLIENT_LIST:
1164 0 : page_down_client(sel, row);
1165 0 : break;
1166 : case PAGE_BACKUP_LIST:
1167 0 : page_down_backup(sel, row);
1168 0 : break;
1169 : case PAGE_BACKUP_LOGS:
1170 0 : break;
1171 : case PAGE_VIEW_LOG:
1172 0 : break;
1173 : }
1174 0 : }
1175 :
1176 0 : static int parse_stdin_data(struct asfd *asfd, struct sel *sel, int count)
1177 : {
1178 : static int ch;
1179 0 : if(asfd->rbuf->len!=sizeof(ch))
1180 : {
1181 : logp("Unexpected input length in %s: %d\n",
1182 0 : __func__, asfd->rbuf->len);
1183 0 : return -1;
1184 : }
1185 0 : memcpy(&ch, asfd->rbuf->buf, sizeof(ch));
1186 0 : switch(ch)
1187 : {
1188 : case 'q':
1189 : case 'Q':
1190 0 : return 1;
1191 : case 't':
1192 : case 'T':
1193 0 : if(toggle) toggle=0;
1194 0 : else toggle=1;
1195 0 : break;
1196 : case KEY_UP:
1197 : case 'k':
1198 : case 'K':
1199 0 : up(sel);
1200 0 : break;
1201 : case KEY_DOWN:
1202 : case 'j':
1203 : case 'J':
1204 0 : down(sel);
1205 0 : break;
1206 : case KEY_LEFT:
1207 : case 'h':
1208 : case 'H':
1209 0 : left(sel);
1210 0 : break;
1211 : case KEY_RIGHT:
1212 : case 'l':
1213 : case 'L':
1214 : case KEY_ENTER:
1215 : case '\n':
1216 : case ' ':
1217 0 : right(sel);
1218 0 : break;
1219 : case KEY_PPAGE:
1220 0 : page_up(sel);
1221 0 : break;
1222 : case KEY_NPAGE:
1223 0 : page_down(sel);
1224 0 : break;
1225 : case -1:
1226 0 : logp("Error on stdin\n");
1227 0 : return -1;
1228 : }
1229 :
1230 0 : return 0;
1231 : }
1232 : #endif
1233 :
1234 0 : static int parse_data(struct asfd *asfd, struct sel *sel, int count)
1235 : {
1236 : #ifdef HAVE_NCURSES_H
1237 0 : if(actg==ACTION_STATUS && asfd->streamtype==ASFD_STREAM_NCURSES_STDIN)
1238 0 : return parse_stdin_data(asfd, sel, count);
1239 : #endif
1240 0 : switch(json_input(asfd, sel))
1241 : {
1242 : // 0 means carry on.
1243 : // 1 means it got to the end of the JSON statement.
1244 : // Anything else means an error.
1245 0 : case 0: return 0;
1246 0 : case 1: return 0;
1247 0 : default: return -1;
1248 : }
1249 : }
1250 :
1251 0 : static int main_loop(struct async *as, enum action act, struct conf **confs)
1252 : {
1253 0 : int ret=-1;
1254 0 : char *client=NULL;
1255 0 : int count=0;
1256 0 : struct asfd *asfd=NULL;
1257 0 : struct asfd *sfd=as->asfd; // Server asfd.
1258 0 : int reqdone=0;
1259 0 : struct sel *sel=NULL;
1260 0 : const char *orig_client=get_string(confs[OPT_ORIG_CLIENT]);
1261 :
1262 0 : if(!(sel=sel_alloc()))
1263 0 : goto error;
1264 0 : sel->page=PAGE_CLIENT_LIST;
1265 :
1266 0 : if(orig_client && !client)
1267 : {
1268 0 : client=strdup_w(orig_client, __func__);
1269 0 : sel->page=PAGE_BACKUP_LIST;
1270 : }
1271 :
1272 : while(1)
1273 : {
1274 0 : if(need_status(sel) && !reqdone)
1275 : {
1276 0 : char *req=NULL;
1277 0 : if(sel->page>PAGE_CLIENT_LIST)
1278 : {
1279 0 : if(client) req=client;
1280 0 : else if(sel->client) req=sel->client->name;
1281 : }
1282 0 : if(request_status(sfd,
1283 0 : req, sel, confs)) goto error;
1284 0 : if(act==ACTION_STATUS_SNAPSHOT)
1285 0 : reqdone=1;
1286 : }
1287 :
1288 0 : if(as->read_write(as))
1289 : {
1290 : // FIX THIS - an exception is thrown when the console
1291 : // is resized.
1292 : /*
1293 : if(sfd->want_to_remove)
1294 : {
1295 : sfd->want_to_remove=0;
1296 : continue;
1297 : }
1298 : */
1299 0 : logp("Exiting main loop\n");
1300 0 : goto error;
1301 : }
1302 :
1303 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
1304 0 : while(asfd->rbuf->buf)
1305 : {
1306 0 : switch(parse_data(asfd, sel, count))
1307 : {
1308 0 : case 0: break;
1309 0 : case 1: goto end;
1310 0 : default: goto error;
1311 : }
1312 0 : iobuf_free_content(asfd->rbuf);
1313 0 : if(asfd->parse_readbuf(asfd))
1314 0 : goto error;
1315 : }
1316 :
1317 0 : if(!sel->client) sel->client=sel->clist;
1318 0 : if(!sel->backup && sel->client) sel->backup=sel->client->bu;
1319 :
1320 : #ifdef HAVE_NCURSES_H
1321 0 : if(act==ACTION_STATUS
1322 0 : && update_screen(sel, confs))
1323 0 : goto error;
1324 0 : refresh();
1325 : #endif
1326 :
1327 0 : if(act==ACTION_STATUS_SNAPSHOT
1328 0 : && sel->gotfirstresponse)
1329 : {
1330 0 : if(update_screen(sel, confs))
1331 0 : goto error;
1332 : // FIX THIS - should probably set up stdout with an
1333 : // asfd.
1334 0 : printf("\n");
1335 0 : break;
1336 : }
1337 : }
1338 :
1339 : end:
1340 0 : ret=0;
1341 : error:
1342 0 : sel_free(&sel);
1343 0 : return ret;
1344 : }
1345 :
1346 : #ifdef HAVE_NCURSES_H
1347 0 : static void ncurses_init(void)
1348 : {
1349 0 : initscr();
1350 0 : start_color();
1351 0 : use_default_colors();
1352 0 : raw();
1353 0 : keypad(stdscr, TRUE);
1354 0 : noecho();
1355 0 : curs_set(0);
1356 0 : halfdelay(3);
1357 : //nodelay(stdscr, TRUE);
1358 0 : }
1359 : #endif
1360 :
1361 0 : static pid_t fork_monitor(int *csin, int *csout, struct conf **confs)
1362 : {
1363 0 : int a=0;
1364 : char *args[12];
1365 :
1366 : // FIX THIS: get all args from configuration.
1367 0 : args[a++]=(char *)"/usr/sbin/burp";
1368 0 : args[a++]=(char *)"-c";
1369 0 : args[a++]=get_string(confs[OPT_CONFFILE]);
1370 0 : args[a++]=(char *)"-a";
1371 0 : args[a++]=(char *)"m";
1372 0 : args[a++]=NULL;
1373 :
1374 0 : return forkchild_fd(csin, csout, NULL, args[0], args);
1375 : }
1376 :
1377 0 : int status_client_ncurses(enum action act, struct conf **confs)
1378 : {
1379 0 : int csin=-1;
1380 0 : int csout=-1;
1381 0 : int ret=-1;
1382 0 : pid_t childpid=-1;
1383 0 : struct async *as=NULL;
1384 0 : const char *monitor_logfile=get_string(confs[OPT_MONITOR_LOGFILE]);
1385 :
1386 : #ifdef HAVE_NCURSES_H
1387 0 : actg=act; // So that the sighandler can call endwin().
1388 : #else
1389 : if(act==ACTION_STATUS)
1390 : {
1391 : printf("To use the live status monitor, you need to recompile with ncurses support.\n");
1392 : goto end;
1393 : }
1394 : #endif
1395 :
1396 0 : setup_signals();
1397 :
1398 : // Fork a burp child process that will contact the server over SSL.
1399 : // We will read and write from and to its stdout and stdin.
1400 0 : if((childpid=fork_monitor(&csin, &csout, confs))<0)
1401 0 : goto end;
1402 : //printf("childpid: %d\n", childpid);
1403 0 : set_non_blocking(csin);
1404 0 : set_non_blocking(csout);
1405 :
1406 0 : if(!(as=async_alloc())
1407 0 : || as->init(as, 0)
1408 0 : || !setup_asfd(as, "monitor stdin", &csin, NULL,
1409 0 : ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_WRITE, -1, confs)
1410 0 : || !setup_asfd(as, "monitor stdout", &csout, NULL,
1411 0 : ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_READ, -1, confs))
1412 0 : goto end;
1413 : //printf("ml: %s\n", monitor_logfile);
1414 : #ifdef HAVE_NCURSES_H
1415 0 : if(actg==ACTION_STATUS)
1416 : {
1417 0 : int stdinfd=fileno(stdin);
1418 0 : if(!setup_asfd(as, "stdin", &stdinfd, NULL,
1419 : ASFD_STREAM_NCURSES_STDIN, ASFD_FD_CLIENT_NCURSES_READ,
1420 0 : -1, confs))
1421 0 : goto end;
1422 0 : ncurses_init();
1423 : }
1424 : #endif
1425 0 : if(monitor_logfile
1426 0 : && !(lfzp=fzp_open(monitor_logfile, "wb")))
1427 0 : goto end;
1428 0 : log_fzp_set_direct(lfzp);
1429 :
1430 0 : if(json_input_init()) goto end;
1431 :
1432 0 : ret=main_loop(as, act, confs);
1433 : end:
1434 : #ifdef HAVE_NCURSES_H
1435 0 : if(actg==ACTION_STATUS) endwin();
1436 : #endif
1437 0 : if(ret) logp("%s exiting with error: %d\n", __func__, ret);
1438 0 : json_input_free();
1439 0 : fzp_close(&lfzp);
1440 0 : async_asfd_free_all(&as);
1441 0 : close_fd(&csin);
1442 0 : close_fd(&csout);
1443 0 : return ret;
1444 : }
|