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