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