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