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