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