source: branches/stable/mondo/mondo/common/newt-specific.c @ 541

Last change on this file since 541 was 541, checked in by bcornec, 13 years ago

Stable is reverted to r436 (2.0.7) to put it in line with 2.0.8 and start from there over

  • Property svn:keywords set to Id
File size: 47.2 KB
Line 
1/* newt-specific.c
2   $Id: newt-specific.c 541 2006-05-13 18:47:23Z bcornec $
3
4  subroutines which do display-type things
5  and use the newt library to do them
6.
7
810/02
9- tell user not to bother mailing list unless snapshot
10
1107/09
12- finish() calls g_erase_tmpdir_and_scratchdir to erase
13  tmpdir and scratchdir at end
14
1506/25
16- tried to fix newtFinished() segfault
17
1804/13/2004
19- lots of char[]'s are now *char's
20
2110/09/2003
22- allow DVD option for text-mode which_backup_type() too
23
2409/28
25- log_to_screen() now takes printf-like parameters
26
2709/26
28- b5 now means dvd (was udev)
29
3009/16
31- echo fatal error to screen before exiting
32- working on fatal_error()
33- swapped g_blurb2 and g_blurb3 in a few places to fix a GUI problem;
34  it shouldn't have worked! :) I think there's a mem-leak somewhere
35
3609/13
37- changed some '\n' occurrences to '\r\n'
38
3909/09
40- fixed silly bug in log_to_screen()
41
4207/02
43- modified popup_and_get_string()
44
4505/03
46- cleaned up fatal_error()
47
4804/30
49- fixed popup_changelist_*()
50
5104/27
52- replace newtFinished() and newtInit() with
53  newtSuspend() and newtResume()
54
5504/25
56- after comparing, popup the changelist for the user
57- moved the relevant code from compare_to_cds() into
58  compare_mode(), so that tape users may benefit too
59
6004/24
61- added lots of assert()'s and log_OS_error()'s
62- cleaned up a few uninitialized strings (valgrind)
63
6404/22
65- line 1181 - 'read from' (not 'restoring from')
66
6703/15/2003
68- fixed potentially infinite loop in log_to_screen (Tom Mortell)
69
7012/04/2002
71- changed "Pick file" to "Non-matching files"
72
7311/28
74- finish() now unregisters Mondo's pid
75
7610/28
77- unmount tmpfs if fatal_error
78
7910/04
80- more XMondo-related work
81- added some =NULL's in a few places
82
8309/01 - 09/30
84- write log_to_screen()'s string to stdout if in text mode
85- update_progress_form_FULL(), update_evalcall_form(),
86  popup_and_*(), ask_me_yes_or_no() now write
87  XMondo-friendly info to stdout if in text mode
88- if fatal error then popup and say what the fatal error is
89- run_program_and_log_output() now takes boolean operator to specify
90  whether it will log its activities in the event of _success_
91- added popup_changelist_from_file(char*source_file, char*topic, void*call_if_entry_selected(void*));
92
9308/07
94- added some functions to let user choose backup dev + format
95
9607/27
97- created
98*/
99
100
101/**
102 * @file
103 * Functions for doing display-type things with the Newt library.
104 */
105
106#define MAX_NEWT_COMMENT_LEN 200
107
108#if __cplusplus
109extern "C" {
110#endif
111
112#include "my-stuff.h"
113#include "mondostructures.h"
114#include "newt-specific.h"
115#include "libmondo-string-EXT.h"
116#include "libmondo-files-EXT.h"
117#include "libmondo-devices-EXT.h"
118#include "libmondo-tools-EXT.h"
119#include "libmondo-fork-EXT.h"
120#include "libmondo-gui-EXT.h"
121#include "lib-common-externs.h"
122
123/*@unused@*/
124//static char cvsid[] = "$Id: newt-specific.c 541 2006-05-13 18:47:23Z bcornec $";
125
126    extern pid_t g_mastermind_pid;
127    extern char *g_tmpfs_mountpt;
128    extern char *g_boot_mountpt;
129    extern char *g_mondo_home;
130
131    extern void set_signals(int);
132
133/**
134 * @addtogroup globalGroup
135 * @{
136 */
137/**
138 * Whether we are currently in a nested call of fatal_error().
139 */
140    bool g_exiting = FALSE;
141
142/**
143 * Padding below the Newt components, to overcome bugs in Newt.
144 */
145    char g_haharrrrr[500];
146
147
148    newtComponent g_timeline = NULL,    ///< The line of the progress form that shows the time elapsed/remaining
149        g_percentline = NULL,   ///< The line of the progress form that shows the percent completed/remaining
150        g_scale = NULL,         ///< The progress bar component in the progress form
151        g_progressForm = NULL,  ///< The progress form component itself
152        g_blurb1 = NULL,        ///< The component for line 1 of the blurb in the progress form
153        g_blurb2 = NULL,        ///< The component for line 2 of the blurb in the progress form
154        g_blurb3 = NULL,        ///< The component for line 3 (updated continuously) of the blurb in the progress form
155        g_label = NULL;         ///< ????? @bug ?????
156
157/**
158 * Padding above the Newt components, to overcome bugs in Newt.
159 */
160    char g_jim_lad_yarr[500];
161    char **err_log_lines = NULL,    ///< The list of log lines to show on the screen.
162        g_blurb_str_1[MAX_NEWT_COMMENT_LEN] = "",   ///< The string for line 1 of the blurb in the progress form
163        g_blurb_str_2[MAX_NEWT_COMMENT_LEN] = "",   ///< The string for line 2 of the blurb in the progress form
164        g_blurb_str_3[MAX_NEWT_COMMENT_LEN] = "";   ///< The string for line 3 (updated continuously) of the blurb in the progress form
165    newtComponent g_isoform_main = NULL,    ///< The evalcall form component itself
166        g_isoform_header = NULL,    ///< The component for the evalcall form title
167        g_isoform_scale = NULL, ///< The progress bar component in the evalcall form
168        g_isoform_timeline = NULL,  ///< The line of the evalcall form that shows the time elapsed/remaining
169        g_isoform_pcline = NULL;    ///< The line of the evalcall form that shows the percent completed/remaining
170    long g_isoform_starttime;   ///< The time (in seconds since the epoch) that the evalcall form was opened.
171    int g_isoform_old_progress = -1;    ///< The most recent progress update of the evalcall form (percent).
172    char g_isoform_header_str[MAX_STR_LEN] = "                                                                                                               "; ///< The string for the evalcall form title.
173    int g_mysterious_dot_counter;   ///< The counter for the twirling baton (/ | \\ - ...) on percentage less than 3
174    int g_noof_log_lines = 6;   ///< The number of lines to show in the log at the bottom of the screen.
175    int g_noof_rows = 25;       ///< The number of rows on the screen.
176
177    int g_currentY = 3;         ///< The row to write background progress messages to. Incremented each time a message is written.
178    extern int g_current_media_number;
179    pid_t g_main_pid = 0;       ///< The PID of the main Mondo process.
180    long g_maximum_progress = 999;  ///< The maximum amount of progress (100%) for the currently opened progress form.
181    long g_current_progress = -999; ///< The current amount of progress (filelist #, etc.) for the currently opened progress form.
182    long g_start_time = 0;      ///< The time (in seconds since the epoch) that the progress form was opened.
183    bool g_text_mode = TRUE;    ///< If FALSE, use a newt interface; if TRUE, use an ugly (but more compatible) dumb terminal interface.
184    char g_xmondo_stdin[MAX_NEWT_COMMENT_LEN],  ///< ... @bug Unneeded w/current XMondo.
185     g_xmondo_stdout[MAX_NEWT_COMMENT_LEN]; ///< .... @bug Unneeded w/current XMondo.
186    bool g_called_by_xmondo = FALSE;    ///< @bug Unneeded w/current XMondo.
187    char *g_erase_tmpdir_and_scratchdir;    ///< The command to run to erase the tmpdir and scratchdir at the end of Mondo.
188    char *g_selfmounted_isodir; ///< Holds the NFS mountpoint if mounted via mondoarchive.
189
190/* @} - end of globalGroup */
191
192//int g_fd_in=-1, g_fd_out=-1;
193
194    void popup_and_OK(char *);
195
196
197/**
198 * @addtogroup guiGroup
199 * @{
200 */
201/**
202 * Ask the user a yes/no question.
203 * @param prompt The question to ask the user.
204 * @return TRUE for yes; FALSE for no.
205 */
206     bool ask_me_yes_or_no(char *prompt) {
207
208        /*@ buffers ********************************************************** */
209        char *tmp;
210        int i;
211
212         tmp = malloc(MAX_NEWT_COMMENT_LEN);
213         assert_string_is_neither_NULL_nor_zerolength(prompt);
214
215        if (g_text_mode) {
216            while (1) {
217                system("sync");
218                printf
219                    ("---promptdialogYN---1--- %s\r\n---promptdialogYN---Q--- [yes] [no] ---\r\n--> ",
220                     prompt);
221                (void) fgets(tmp, MAX_NEWT_COMMENT_LEN, stdin);
222                if (tmp[strlen(tmp) - 1] == '\n')
223                    tmp[strlen(tmp) - 1] = '\0';
224
225                i = (int) strlen(tmp);
226                if (i > 0 && tmp[i - 1] < 32) {
227                    tmp[i - 1] = '\0';
228                }
229                if (strstr("yesYES", tmp)) {
230                    paranoid_free(tmp);
231                    return (TRUE);
232                } else if (strstr("NOno", tmp)) {
233                    paranoid_free(tmp);
234                    return (FALSE);
235                } else {
236                    system("sync");
237                    printf
238                        ("Please enter either YES or NO (or yes or no, or y or n, or...)\n");
239                }
240            }
241        } else {
242            paranoid_free(tmp);
243            return (popup_with_buttons(prompt, "Yes", "No"));
244        }
245    }
246
247
248/**
249 * Give the user the opportunity to continue the current operation (OK)
250 * or cancel it (Cancel).
251 * @param prompt The string to be displayed.
252 * @return TRUE for OK, FALSE for Cancel.
253 */
254    bool ask_me_OK_or_cancel(char *prompt) {
255
256        /*@ buffer *********************************************************** */
257        char *tmp;
258        int i;
259
260        tmp = malloc(MAX_NEWT_COMMENT_LEN);
261        assert_string_is_neither_NULL_nor_zerolength(prompt);
262        if (g_text_mode) {
263            system("sync");
264            printf
265                ("---promptdialogOKC---1--- %s\r\n---promptdialogOKC---Q--- [OK] [Cancel] ---\r\n--> ",
266                 prompt);
267            (void) fgets(tmp, MAX_NEWT_COMMENT_LEN, stdin);
268            if (tmp[strlen(tmp) - 1] == '\n')
269                tmp[strlen(tmp) - 1] = '\0';
270
271            i = (int) strlen(tmp);
272            if (i > 0 && tmp[i - 1] < 32) {
273                tmp[i - 1] = '\0';
274            }
275            if (strstr("okOKOkYESyes", tmp)) {
276                paranoid_free(tmp);
277                return (TRUE);
278            } else {
279                paranoid_free(tmp);
280                return (FALSE);
281            }
282        } else {
283            paranoid_free(tmp);
284            return (popup_with_buttons(prompt, " Okay ", "Cancel"));
285        }
286    }
287
288
289
290/**
291 * Close the currently opened evalcall form.
292 */
293    void
294     close_evalcall_form(void) {
295        if (g_text_mode) {
296            return;
297        }
298        if (g_isoform_main == NULL) {
299            return;
300        }
301        update_evalcall_form(100);
302        usleep(500000);
303        if (g_text_mode) {
304            log_msg(2, "Closing evalcall form");
305            return;
306        }
307        newtPopHelpLine();
308        newtFormDestroy(g_isoform_main);
309        newtPopWindow();
310        g_isoform_main = NULL;
311        g_isoform_old_progress = -1;
312    }
313
314
315/**
316 * Close the currently opened progress form.
317 */
318    void
319     close_progress_form() {
320        if (g_text_mode) {
321            return;
322        }
323        if (g_current_progress == -999) {
324            log_msg(2,
325                    "Trying to close the progress form when it ain't open!");
326            return;
327        }
328        g_current_progress = g_maximum_progress;
329        update_progress_form("Complete");
330        sleep(1);
331        if (g_text_mode) {
332            log_msg(2, "Closing progress form");
333            return;
334        }
335        newtPopHelpLine();
336        newtFormDestroy(g_progressForm);
337        newtPopWindow();
338        g_progressForm = NULL;
339        g_current_progress = -999;
340    }
341
342
343
344
345/**
346 * Exit Mondo with a fatal error.
347 * @param error_string The error message to present to the user before exiting.
348 * @note This function never returns.
349 */
350    void
351     fatal_error(char *error_string) {
352        /*@ buffers ***************************************************** */
353        char fatalstr[MAX_NEWT_COMMENT_LEN] =
354            "-------FATAL ERROR---------";
355        char *tmp;
356        char *command;
357        static bool already_exiting = FALSE;
358        int i;
359
360        /*@ end vars **************************************************** */
361
362        malloc_string(command);
363        tmp = malloc(MAX_NEWT_COMMENT_LEN);
364        set_signals(FALSE);     // link to external func
365        g_exiting = TRUE;
366        log_msg(1, "Fatal error received - '%s'", error_string);
367        printf("Fatal error... %s\n", error_string);
368        if (getpid() == g_mastermind_pid) {
369            log_msg(2, "mastermind %d is exiting", (int) getpid());
370            kill(g_main_pid, SIGTERM);
371            paranoid_free(tmp);
372            finish(1);
373        }
374
375        if (getpid() != g_main_pid) {
376            if (g_mastermind_pid != 0 && getpid() != g_mastermind_pid) {
377                log_msg(2, "non-m/m %d is exiting", (int) getpid());
378                kill(g_main_pid, SIGTERM);
379                paranoid_free(tmp);
380                finish(1);
381            }
382        }
383
384        log_msg(3, "OK, I think I'm the main PID.");
385        if (already_exiting) {
386            log_msg(3, "...I'm already exiting. Give me time, Julian!");
387            paranoid_free(tmp);
388            finish(1);
389        }
390
391        already_exiting = TRUE;
392        log_msg(2, "I'm going to do some cleaning up now.");
393        paranoid_system("killall mindi 2> /dev/null");
394        kill_anything_like_this("/mondo/do-not");
395        kill_anything_like_this("tmp.mondo");
396        kill_anything_like_this("ntfsclone");
397        sync();
398        sprintf(tmp, "umount %s", g_tmpfs_mountpt);
399        chdir("/");
400        for (i = 0; i < 10 && run_program_and_log_output(tmp, 5); i++) {
401            log_msg(2, "Waiting for child processes to terminate");
402            sleep(1);
403            run_program_and_log_output(tmp, 5);
404        }
405
406        if (g_erase_tmpdir_and_scratchdir[0]) {
407            run_program_and_log_output(g_erase_tmpdir_and_scratchdir, 5);
408        }
409
410        if (g_selfmounted_isodir) {
411            sprintf(command, "umount %s", g_selfmounted_isodir);
412            run_program_and_log_output(command, 5);
413            sprintf(command, "rmdir %s", g_selfmounted_isodir);
414            run_program_and_log_output(command, 5);
415        }
416
417        if (!g_text_mode) {
418            log_msg(0, fatalstr);
419            log_msg(0, error_string);
420            //      popup_and_OK (error_string);
421            newtFinished();
422        }
423
424        printf("---FATALERROR--- %s\n", error_string);
425        system
426            ("gzip -9c /var/log/mondo-archive.log > /tmp/MA.log.gz 2> /dev/null");
427        printf
428                ("If you require technical support, please contact the mailing list.\n");
429        printf("See http://www.mondorescue.org for details.\n");
430        printf
431                ("The list's members can help you, if you attach that file to your e-mail.\n");
432        printf("Log file: %s\n", MONDO_LOGFILE);
433        if (does_file_exist("/tmp/MA.log.gz")) {
434            printf
435                ("FYI, I have gzipped the log and saved it to /tmp/MA.log.gz\n");
436        }
437        printf("Mondo has aborted.\n");
438        register_pid(0, "mondo");   // finish() does this too, FYI
439        if (!g_main_pid) {
440            log_msg(3, "FYI - g_main_pid is blank");
441        }
442        paranoid_free(tmp);
443        paranoid_free(command);
444        finish(254);
445    }
446
447
448
449/**
450 * Exit Mondo normally.
451 * @param signal The exit code (0 indicates a successful backup; 1 for Mondo means the
452 * user aborted; 254 means a fatal error occured).
453 * @note This function never returns.
454 */
455    void
456     finish(int signal) {
457        char *command;
458        malloc_string(command);
459
460        /*  if (signal==0) { popup_and_OK("Please press <enter> to quit."); } */
461
462        /* newtPopHelpLine(); */
463
464        register_pid(0, "mondo");
465        chdir("/");
466        run_program_and_log_output("umount " MNT_CDROM, FALSE);
467        run_program_and_log_output("rm -Rf /mondo.scratch.* /tmp.mondo.*",
468                                   FALSE);
469        if (g_erase_tmpdir_and_scratchdir) {
470            run_program_and_log_output(g_erase_tmpdir_and_scratchdir, 1);
471        }
472        if (g_selfmounted_isodir) {
473            sprintf(command, "umount %s", g_selfmounted_isodir);
474            run_program_and_log_output(command, 1);
475            sprintf(command, "rmdir %s", g_selfmounted_isodir);
476            run_program_and_log_output(command, 1);
477        }
478//  iamhere("foo");
479        /* system("clear"); */
480//  iamhere("About to call newtFinished");
481        if (!g_text_mode) {
482            if (does_file_exist("/THIS-IS-A-RAMDISK")) {
483                log_msg(1, "Calling newtFinished()");
484                newtFinished();
485            } else {
486                log_msg(1, "Calling newtSuspend()");
487                newtSuspend();
488            }
489        }
490//  system("clear");
491//  iamhere("Finished calling newtFinished");
492        printf("Execution run ended; result=%d\n", signal);
493        printf("Type 'less %s' to see the output log\n", MONDO_LOGFILE);
494        free_libmondo_global_strings();
495        exit(signal);
496    }
497
498
499
500
501
502/**
503 * Log the last @p g_noof_log_lines lines of @p filename that match @p
504 * grep_for_me to the screen.
505 * @param filename The file to give the end of.
506 * @param grep_for_me If not "", then only give lines in @p filename that match this regular expression.
507 */
508    void
509     log_file_end_to_screen(char *filename, char *grep_for_me) {
510
511        /*@ buffers ********************************************************** */
512        char *command;
513        char *tmp;
514
515        /*@ pointers ********************************************************* */
516        FILE *fin;
517
518        /*@ int ************************************************************** */
519        int i = 0;
520
521        malloc_string(command);
522        malloc_string(tmp);
523        assert_string_is_neither_NULL_nor_zerolength(filename);
524        assert(grep_for_me != NULL);
525
526        if (!does_file_exist(filename)) {
527            paranoid_free(command);
528            paranoid_free(tmp);
529            return;
530        }
531        if (grep_for_me[0] != '\0') {
532            sprintf(command, "grep '%s' %s | tail -n%d",
533                    grep_for_me, filename, g_noof_log_lines);
534        } else {
535            sprintf(command, "tail -n%d %s", g_noof_log_lines,
536                    filename);
537        }
538        fin = popen(command, "r");
539        if (!fin) {
540            log_OS_error(command);
541        } else {
542            for (i = 0; i < g_noof_log_lines; i++) {
543                for (err_log_lines[i][0] = '\0';
544                     strlen(err_log_lines[i]) < 2 && !feof(fin);) {
545                    (void) fgets(err_log_lines[i], MAX_NEWT_COMMENT_LEN,
546                                 fin);
547                    strip_spaces(err_log_lines[i]);
548                    if (!strncmp(err_log_lines[i], "root:", 5)) {
549                        strcpy(tmp, err_log_lines[i] + 6);
550                        strcpy(err_log_lines[i], tmp);
551                    }
552                    if (feof(fin)) {
553                        break;
554                    }
555                }
556            }
557            paranoid_pclose(fin);
558        }
559        refresh_log_screen();
560        paranoid_free(command);
561        paranoid_free(tmp);
562    }
563
564
565/**
566 * Log a message to the screen.
567 * @param fmt A printf-style format string to write. The following parameters are its arguments.
568 * @note The message is also written to the logfile.
569 */
570    void
571     log_to_screen(const char *fmt, ...) {
572
573        /*@ int ************************************************************** */
574        int i = 0;
575        int j = 0;
576        va_list args;
577
578        /*@ buffers ********************************************************** */
579        char *output;
580
581        malloc_string(output);
582
583        va_start(args, fmt);
584        vsprintf(output, fmt, args);
585        log_msg(0, output);
586        output[80] = '\0';
587        va_end(args);
588        i = (int) strlen(output);
589        if (i > 0 && output[i - 1] < 32) {
590            output[i - 1] = '\0';
591        }
592
593        if (err_log_lines) {
594            for (i = 1; i < g_noof_log_lines; i++) {
595                strcpy(err_log_lines[i - 1],
596                       "                                                                                ");
597                strcpy(err_log_lines[i - 1], err_log_lines[i]);
598            }
599        }
600        while (strlen(output) > 0 && output[strlen(output) - 1] < 32) {
601            output[strlen(output) - 1] = '\0';
602        }
603        for (j = 0; j < (int) strlen(output); j++) {
604            if (output[j] < 32) {
605                output[j] = ' ';
606            }
607        }
608        if (err_log_lines)
609            strcpy(err_log_lines[g_noof_log_lines - 1], output);
610        if (g_text_mode) {
611            printf("%s\n", output);
612        } else {
613            refresh_log_screen();
614        }
615        paranoid_free(output);
616    }
617
618
619
620
621/**
622 * Write a string to the root window at (@p x, @p y) and also to the logfile.
623 * @param y The row to write the string to.
624 * @param x The column to write the string to.
625 * @param output The string to write.
626 */
627    void
628     mvaddstr_and_log_it(int y, int x, char *output) {
629        assert_string_is_neither_NULL_nor_zerolength(output);
630        log_msg(0, output);
631        if (g_text_mode) {
632            printf("%s\n", output);
633        } else {
634            newtDrawRootText(x, y, output);
635            newtRefresh();
636        }
637    }
638
639
640
641
642/**
643 * Open an evalcall form with title @p ttl.
644 * @param ttl The title to use for the evalcall form.
645 */
646    void
647     open_evalcall_form(char *ttl) {
648
649        /*@ buffers ********************************************************* */
650        char *title;
651        char *tmp;
652
653        /*@ initialize ****************************************************** */
654        g_isoform_old_progress = -1;
655        g_mysterious_dot_counter = 0;
656        malloc_string(title);
657        malloc_string(tmp);
658
659        assert(ttl != NULL);
660        strcpy(title, ttl);
661        strcpy(g_isoform_header_str, title);
662//  center_string (title, 80);
663        if (g_text_mode) {
664            log_msg(0, title);
665        } else {
666            strcpy(tmp, title);
667            center_string(tmp, 80);
668            newtPushHelpLine(tmp);
669        }
670        center_string(g_isoform_header_str, 36);
671        g_isoform_starttime = get_time();
672        if (g_text_mode) {
673            log_msg(0, g_isoform_header_str);
674        } else {
675            g_isoform_header = newtLabel(1, 1, g_isoform_header_str);
676            g_isoform_scale = newtScale(3, 3, 34, 100);
677            //      newtOpenWindow (20, 6, 40, 7, title);      // "Please Wait");
678            newtCenteredWindow(40, 7, title);
679            g_isoform_main = newtForm(NULL, NULL, 0);
680            g_isoform_timeline = newtLabel(1, 5, "This is the timeline");
681            g_isoform_pcline = newtLabel(1, 6, "This is the pcline");
682            newtFormAddComponents(g_isoform_main, g_isoform_timeline,
683                                  g_isoform_pcline, g_isoform_header,
684                                  g_isoform_scale, NULL);
685            newtRefresh();
686        }
687        update_evalcall_form(0);
688        paranoid_free(tmp);
689        paranoid_free(title);
690    }
691
692
693
694/**
695 * Open a progress form with title @p title.
696 * @param title The title to use for the progress form (will be put in the title bar on Newt).
697 * @param b1 The first line of the blurb; generally static.
698 * @param b2 The second line of the blurb; generally static.
699 * @param b3 The third line of the blurb; generally dynamic (it is passed
700 * to update_evalcall_form() every time).
701 * @param max_val The maximum amount of progress (number of filesets, etc.)
702 */
703    void
704     open_progress_form(char *title, char *b1, char *b2, char *b3,
705                        long max_val) {
706
707        /*@ buffers ********************************************************* */
708        char *b1c;
709        char *blurb1;
710        char *blurb2;
711        char *blurb3;
712
713        /*@ initialize ****************************************************** */
714        g_mysterious_dot_counter = 0;
715
716        malloc_string(b1c);
717        malloc_string(blurb1);
718        malloc_string(blurb2);
719        malloc_string(blurb3);
720
721        assert(title != NULL);
722        assert(b1 != NULL);
723        assert(b2 != NULL);
724        assert(b3 != NULL);
725
726        strcpy(blurb1, b1);
727        strcpy(blurb2, b2);
728        strcpy(blurb3, b3);
729        strcpy(b1c, b1);
730        center_string(b1c, 80);
731        if (max_val <= 0) {
732            max_val = 1;
733        }
734
735        g_start_time = get_time();
736        g_maximum_progress = max_val;
737        g_current_progress = 0;
738        strcpy(g_blurb_str_1, blurb1);
739        strcpy(g_blurb_str_2, blurb3);
740        strcpy(g_blurb_str_3, blurb2);
741        if (g_text_mode) {
742            log_msg(0, blurb1);
743            log_msg(0, blurb2);
744            log_msg(0, blurb3);
745        } else {
746            g_blurb1 = newtLabel(2, 1, blurb1);
747            g_blurb2 = newtLabel(2, 2, blurb3);
748            g_blurb3 = newtLabel(2, 4, blurb2);
749            //      newtOpenWindow (10, 4, 60, 11, title);
750            newtCenteredWindow(60, 11, title);
751            g_scale = newtScale(3, 6, 54, g_maximum_progress);
752            g_progressForm = newtForm(NULL, NULL, 0);
753            g_percentline = newtLabel(10, 9, "This is the percentline");
754            g_timeline = newtLabel(10, 8, "This is the timeline");
755            newtFormAddComponents(g_progressForm, g_percentline,
756                                  g_timeline, g_scale, g_blurb1, g_blurb3,
757                                  g_blurb2, NULL);
758            newtPushHelpLine(b1c);
759            newtRefresh();
760        }
761        update_progress_form_full(blurb1, blurb2, blurb3);
762        paranoid_free(b1c);
763        paranoid_free(blurb1);
764        paranoid_free(blurb2);
765        paranoid_free(blurb3);
766    }
767
768/**
769 * Give a message to the user in the form of a dialog box (under Newt).
770 * @param prompt The message.
771 */
772    void
773     popup_and_OK(char *prompt) {
774        char ch;
775
776        assert_string_is_neither_NULL_nor_zerolength(prompt);
777
778        log_msg(0, prompt);
779        if (g_text_mode) {
780            printf
781                ("---promptpopup---1--- %s\r\n---promptpopup---Q--- [OK] ---\r\n--> ",
782                 prompt);
783            while (((ch = getchar()) != '\n') && (ch != EOF));
784        } else {
785            (void) popup_with_buttons(prompt, " OK ", "");
786        }
787    }
788
789/**
790 * Ask the user to enter a value.
791 * @param title The title of the dialog box.
792 * @param b The blurb (e.g. what you want the user to enter).
793 * @param output The string to put the user's answer in.
794 * @param maxsize The size in bytes allocated to @p output.
795 * @return TRUE if the user pressed OK, FALSE if they pressed Cancel.
796 */
797    bool popup_and_get_string(char *title, char *b, char *output,
798                              int maxsize) {
799
800        /*@ newt ************************************************************ */
801        newtComponent myForm;
802        newtComponent b_1;
803        newtComponent b_2;
804        newtComponent b_res;
805        newtComponent text;
806        newtComponent type_here;
807
808        /*@ pointers ********************************************************* */
809        char *entry_value;
810
811        /*@ buffers ********************************************************** */
812        char *blurb;
813        char *original_contents;
814
815        blurb = malloc(MAX_NEWT_COMMENT_LEN);
816        original_contents = malloc(MAX_NEWT_COMMENT_LEN);
817        assert_string_is_neither_NULL_nor_zerolength(title);
818        assert(b != NULL);
819        assert(output != NULL);
820
821        if (g_text_mode) {
822            printf
823                ("---promptstring---1--- %s\r\n---promptstring---2--- %s\r\n---promptstring---Q---\r\n-->  ",
824                 title, b);
825            (void) fgets(output, maxsize, stdin);
826            if (output[strlen(output) - 1] == '\n')
827                output[strlen(output) - 1] = '\0';
828            paranoid_free(blurb);
829            paranoid_free(original_contents);
830            return (TRUE);
831        }
832        strcpy(blurb, b);
833        text = newtTextboxReflowed(2, 1, blurb, 48, 5, 5, 0);
834        strcpy(original_contents, output);
835        output[0] = '\0';
836        type_here =
837            newtEntry(2, newtTextboxGetNumLines(text) + 2,
838                      original_contents, 50,
839#ifdef __cplusplus
840                      0, NEWT_FLAG_RETURNEXIT
841#else
842                      (void *) &entry_value, NEWT_FLAG_RETURNEXIT
843#endif
844            );
845        b_1 = newtButton(6, newtTextboxGetNumLines(text) + 4, "  OK  ");
846        b_2 = newtButton(18, newtTextboxGetNumLines(text) + 4, "Cancel");
847        //  newtOpenWindow (8, 5, 54, newtTextboxGetNumLines (text) + 9, title);
848        newtCenteredWindow(54, newtTextboxGetNumLines(text) + 9, title);
849        myForm = newtForm(NULL, NULL, 0);
850        newtFormAddComponents(myForm, text, type_here, b_1, b_2, NULL);
851        center_string(blurb, 80);
852        newtPushHelpLine(blurb);
853        b_res = newtRunForm(myForm);
854        strcpy(output, entry_value);
855        newtPopHelpLine();
856        newtFormDestroy(myForm);
857        newtPopWindow();
858        if (b_res == b_2) {
859            strcpy(output, original_contents);
860            paranoid_free(blurb);
861            paranoid_free(original_contents);
862            return (FALSE);
863        } else {
864            paranoid_free(blurb);
865            paranoid_free(original_contents);
866            return (TRUE);
867        }
868    }
869
870
871/**
872 * Pop up a dialog box with user-defined buttons.
873 * @param p The text to put in the dialog box.
874 * @param button1 The label on the first button.
875 * @param button2 The label on the second button, or "" if you only want one button.
876 * @return TRUE if @p button1 was pushed, FALSE otherwise.
877 */
878    bool popup_with_buttons(char *p, char *button1, char *button2) {
879
880        /*@ buffers *********************************************************** */
881        char *prompt, *tmp;
882
883        /*@ newt ************************************************************** */
884        newtComponent myForm;
885        newtComponent b_1;
886        newtComponent b_2;
887        newtComponent b_res;
888        newtComponent text;
889
890        prompt = malloc(MAX_NEWT_COMMENT_LEN);
891        tmp = malloc(MAX_NEWT_COMMENT_LEN);
892        assert_string_is_neither_NULL_nor_zerolength(p);
893        assert(button1 != NULL);
894        assert(button2 != NULL);
895        if (g_text_mode) {
896            if (strlen(button2) == 0) {
897                printf("%s (%s) --> ", p, button1);
898            } else {
899                printf("%s (%s or %s) --> ", p, button1, button2);
900            }
901            for (tmp[0] = '\0';
902                 strcmp(tmp, button1) && (strlen(button2) == 0
903                                          || strcmp(tmp, button2));) {
904                printf("--> ");
905                (void) fgets(tmp, MAX_NEWT_COMMENT_LEN, stdin);
906            }
907            if (!strcmp(tmp, button1)) {
908                paranoid_free(tmp);
909                paranoid_free(prompt);
910                return (TRUE);
911            } else {
912                paranoid_free(tmp);
913                paranoid_free(prompt);
914                return (FALSE);
915            }
916        }
917
918        strcpy(prompt, p);
919        text = newtTextboxReflowed(1, 1, prompt, 40, 5, 5, 0);
920        b_1 =
921            newtButton(20 -
922                       ((button2[0] !=
923                         '\0') ? strlen(button1) +
924                        2 : strlen(button1) / 2),
925                       newtTextboxGetNumLines(text) + 3, button1);
926        if (button2[0] != '\0') {
927            b_2 =
928                newtButton(24, newtTextboxGetNumLines(text) + 3, button2);
929        } else {
930            b_2 = NULL;
931        }
932        //  newtOpenWindow (25, 5, 46, newtTextboxGetNumLines (text) + 7, "Alert");
933        newtCenteredWindow(46, newtTextboxGetNumLines(text) + 7, "Alert");
934        myForm = newtForm(NULL, NULL, 0);
935        newtFormAddComponents(myForm, text, b_1, b_2, NULL);
936        center_string(prompt, 80);
937        newtPushHelpLine(prompt);
938        b_res = newtRunForm(myForm);
939        newtPopHelpLine();
940        newtFormDestroy(myForm);
941        newtPopWindow();
942        if (b_res == b_1) {
943            paranoid_free(tmp);
944            paranoid_free(prompt);
945            return (TRUE);
946        } else {
947            paranoid_free(tmp);
948            paranoid_free(prompt);
949            return (FALSE);
950        }
951    }
952
953
954
955
956/**
957 * Synchronize the log messages stored in @p err_log_lines with those shown
958 * on the screen.
959 */
960    void
961     refresh_log_screen() {
962
963        /*@ int *********************************************************** */
964        int i = 0;
965
966
967        if (g_text_mode || !err_log_lines) {
968            return;
969        }
970        for (i = g_noof_log_lines - 1; i >= 0; i--) {
971            newtDrawRootText(0, i + g_noof_rows - 1 - g_noof_log_lines,
972                             "                                                                                ");
973        }
974        newtRefresh();
975        for (i = g_noof_log_lines - 1; i >= 0; i--) {
976            err_log_lines[i][79] = '\0';
977            newtDrawRootText(0, i + g_noof_rows - 1 - g_noof_log_lines,
978                             err_log_lines[i]);
979        }
980        newtRefresh();
981    }
982
983
984/**
985 * Set up the Newt graphical environment. If @p g_text_mode is TRUE, then
986 * only allocate some memory.
987 */
988    void
989     setup_newt_stuff() {
990
991        /*@ int *********************************************************** */
992        int i = 0;
993        int cols;
994
995        if (!g_text_mode) {
996            newtInit();
997            newtCls();
998            newtPushHelpLine
999                ("Welcome to Mondo Rescue, by Hugo Rabson and the Internet. All rights reversed.");
1000            /*  newtDrawRootText(28,0,"Welcome to Mondo Rescue"); */
1001            newtDrawRootText(18, 0, WELCOME_STRING);
1002            newtRefresh();
1003            newtGetScreenSize(&cols, &g_noof_rows);
1004            g_noof_log_lines = (g_noof_rows / 5) + 1;
1005        }
1006
1007        err_log_lines =
1008            (char **) malloc(sizeof(char *) * g_noof_log_lines);
1009        if (!err_log_lines) {
1010            fatal_error("Out of memory");
1011        }
1012
1013        for (i = 0; i < g_noof_log_lines; i++) {
1014            err_log_lines[i] = (char *) malloc(MAX_NEWT_COMMENT_LEN);
1015            if (!err_log_lines[i]) {
1016                fatal_error("Out of memory");
1017            }
1018        }
1019
1020        for (i = 0; i < g_noof_log_lines; i++) {
1021            err_log_lines[i][0] = '\0';
1022        }
1023    }
1024
1025
1026/**
1027 * Update the evalcall form to show (<tt>num</tt>/<tt>denom</tt>)*100 %.
1028 * @param num The numerator of the ratio.
1029 * @param denom The denomenator of the ratio.
1030 */
1031    void
1032     update_evalcall_form_ratio(int num, int denom) {
1033
1034        /*@ long ************************************************************ */
1035        long current_time = 0;
1036        long time_taken = 0;
1037        long time_total_est = 0;
1038        long time_remaining = 0;
1039
1040        /*@ buffers ********************************************************** */
1041        char *timeline_str;
1042        char *pcline_str;
1043        char *taskprogress;
1044
1045        /*@ int ************************************************************** */
1046        int percentage = 0;
1047        int i = 0;
1048        int j = 0;
1049
1050        malloc_string(timeline_str);
1051        malloc_string(pcline_str);
1052        malloc_string(taskprogress);
1053        timeline_str[0] = '\0';
1054//  log_it("update_eval_call_form called");
1055        if (num * 100 < denom) {
1056            percentage = 1;
1057        } else {
1058            percentage = (num * 100 + denom / 2) / denom;
1059        }
1060
1061        current_time = get_time();
1062        time_taken = current_time - g_isoform_starttime;
1063        if (num) {
1064            time_total_est = time_taken * denom / num;
1065            time_remaining = time_total_est - time_taken;
1066        } else {
1067            time_remaining = 0;
1068        }
1069        if (!g_text_mode) {
1070            newtLabelSetText(g_isoform_header, g_isoform_header_str);
1071        }
1072        g_mysterious_dot_counter = (g_mysterious_dot_counter + 1) % 27;
1073        if ((percentage < 3 && g_isoform_old_progress < 3)
1074            || percentage > g_isoform_old_progress) {
1075            g_isoform_old_progress = percentage;
1076            sprintf(timeline_str,
1077                    "%2ld:%02ld taken            %2ld:%02ld remaining",
1078                    time_taken / 60, time_taken % 60, time_remaining / 60,
1079                    time_remaining % 60);
1080            if (percentage < 3) {
1081                sprintf(pcline_str, " Working");
1082                for (j = 0; j < g_mysterious_dot_counter; j++) {
1083                    strcat(pcline_str, ".");
1084                }
1085                for (; j < 27; j++) {
1086                    strcat(pcline_str, " ");
1087                }
1088                sprintf(pcline_str + strlen(pcline_str), " %c",
1089                        special_dot_char(g_mysterious_dot_counter));
1090            } else {
1091                sprintf(pcline_str, " %3d%% done              %3d%% to go",
1092                        percentage, 100 - percentage);
1093            }
1094            if (g_text_mode) {
1095                sprintf(taskprogress, "TASK:  [");
1096                for (i = 0; i < percentage; i += 5) {
1097                    strcat(taskprogress, "*");
1098                }
1099                for (; i < 100; i += 5) {
1100                    strcat(taskprogress, ".");
1101                }
1102                if (percentage >= 3) {
1103                    sprintf(taskprogress + strlen(taskprogress),
1104                            "] %3d%% done; %2ld:%02ld to go", percentage,
1105                            time_remaining / 60, time_remaining % 60);
1106                    printf("---evalcall---1--- %s\r\n",
1107                           g_isoform_header_str);
1108                    printf("---evalcall---2--- %s\r\n", taskprogress);
1109                    printf("---evalcall---E---\r\n");
1110                }
1111            } else {
1112                newtScaleSet(g_isoform_scale,
1113                             (unsigned long long) percentage);
1114                newtLabelSetText(g_isoform_pcline, pcline_str);
1115                if (percentage >= 3) {
1116                    newtLabelSetText(g_isoform_timeline, timeline_str);
1117                }
1118            }
1119        }
1120        if (!g_text_mode) {
1121//      log_it("refreshing");
1122            newtRefresh();
1123        }
1124        paranoid_free(timeline_str);
1125        paranoid_free(pcline_str);
1126        paranoid_free(taskprogress);
1127    }
1128
1129
1130
1131/**
1132 * Update the evalcall form to show @p curr %.
1133 * @param curr The current amount of progress (percentage) in the evalcall form.
1134 */
1135    void
1136     update_evalcall_form(int curr) {
1137        update_evalcall_form_ratio(curr, 100);
1138    }
1139
1140
1141
1142/**
1143 * Update the progress form to show @p blurb3 and the current value of
1144 * @p g_maximum_progress.
1145 * @param blurb3 The new third line of the blurb; use @p g_blurb_str_2 (no, that's not a typo) to keep it the same.
1146 */
1147    void
1148     update_progress_form(char *blurb3) {
1149        /*  log_it("update_progress_form --- called"); */
1150        if (g_current_progress == -999) {
1151            /* log_it("You're trying to update progress form when it ain't open. Aww, that's OK. I'll let it go. It's a bit naughty but it's a nonfatal error. No prob, Bob."); */
1152            return;
1153        }
1154        strcpy(g_blurb_str_2, blurb3);
1155        update_progress_form_full(g_blurb_str_1, g_blurb_str_2,
1156                                  g_blurb_str_3);
1157    }
1158
1159
1160/**
1161 * Update the progress form's complete blurb and show @p g_current_progress.
1162 * @param blurb1 The first line of the blurb. Use @p g_blurb_str_1 to keep it unchanged.
1163 * @param blurb2 The second line of the blurb. Use @p g_blurb_str_3 (no, that's not a typo) to keep it the same.
1164 * @param blurb3 The third line of the blurb. Use @p g_blurb_str_2 (no, that's not a typo either) to keep it the same.
1165 */
1166    void
1167     update_progress_form_full(char *blurb1, char *blurb2, char *blurb3) {
1168        /*@ long ***************************************************** */
1169        long current_time = 0;
1170        long time_taken = 0;
1171        long time_remaining = 0;
1172        long time_total_est = 0;
1173
1174        /*@ int ******************************************************* */
1175        int percentage = 0;
1176        int i = 0;
1177
1178        /*@ buffers *************************************************** */
1179        char *percentline_str;
1180        char *timeline_str;
1181        char *taskprogress;
1182        char *tmp;
1183
1184//  log_msg(1, "'%s' '%s' '%s'", blurb1, blurb2, blurb3);
1185        percentline_str = malloc(MAX_NEWT_COMMENT_LEN);
1186        timeline_str = malloc(MAX_NEWT_COMMENT_LEN);
1187        taskprogress = malloc(MAX_NEWT_COMMENT_LEN);
1188        malloc_string(tmp);
1189        if (!g_text_mode) {
1190            assert(blurb1 != NULL);
1191            assert(blurb2 != NULL);
1192            assert(blurb3 != NULL);
1193            assert(g_timeline != NULL);
1194        }
1195
1196        percentline_str[0] = '\0';
1197
1198        current_time = get_time();
1199        time_taken = current_time - g_start_time;
1200        if (g_maximum_progress == 0) {
1201            percentage = 0;
1202        } else {
1203            if (g_current_progress > g_maximum_progress) {
1204                sprintf(tmp,
1205                        "update_progress_form_full(%s,%s,%s) --- g_current_progress=%ld; g_maximum_progress=%ld",
1206                        blurb1, blurb2, blurb3, g_current_progress,
1207                        g_maximum_progress);
1208                log_msg(0, tmp);
1209                g_current_progress = g_maximum_progress;
1210            }
1211            percentage =
1212                (int) ((g_current_progress * 100L) / g_maximum_progress);
1213        }
1214        if (percentage < 1) {
1215            percentage = 1;
1216        }
1217        if (percentage > 100) {
1218            percentage = 100;
1219        }
1220        if (g_current_progress) {
1221            time_total_est =
1222                time_taken * (long) g_maximum_progress /
1223                (long) (g_current_progress);
1224            time_remaining = time_total_est - time_taken;
1225        } else {
1226            time_remaining = 0;
1227        }
1228        g_mysterious_dot_counter = (g_mysterious_dot_counter + 1) % 27;
1229        sprintf(timeline_str,
1230                "%2ld:%02ld taken               %2ld:%02ld remaining  ",
1231                time_taken / 60, time_taken % 60, time_remaining / 60,
1232                time_remaining % 60);
1233        sprintf(percentline_str, " %3d%% done                 %3d%% to go",
1234                percentage, 100 - percentage);
1235
1236        if (g_text_mode) {
1237            printf("---progress-form---1--- %s\r\n", blurb1);
1238            printf("---progress-form---2--- %s\r\n", blurb2);
1239            printf("---progress-form---3--- %s\r\n", blurb3);
1240            printf("---progress-form---E---\n");
1241            sprintf(taskprogress, "TASK:  [");
1242            for (i = 0; i < percentage; i += 5) {
1243                strcat(taskprogress, "*");
1244            }
1245            for (; i < 100; i += 5) {
1246                strcat(taskprogress, ".");
1247            }
1248            if (percentage > 100) {
1249                log_msg(2, "percentage = %d", percentage);
1250            }
1251            sprintf(taskprogress + strlen(taskprogress),
1252                    "] %3d%c", percentage, '%');
1253            sprintf(taskprogress + strlen(taskprogress),
1254                    " done; %2ld:%02ld to go",
1255                    time_remaining / 60, time_remaining % 60);
1256            printf("---progress-form---4--- %s\r\n", taskprogress);
1257        } else {
1258            center_string(blurb1, 54);
1259            center_string(blurb2, 54);
1260            center_string(blurb3, 54);
1261            newtLabelSetText(g_blurb1, blurb1);
1262            newtLabelSetText(g_blurb2, blurb3);
1263            newtLabelSetText(g_blurb3, blurb2);
1264            newtScaleSet(g_scale, (unsigned long long) g_current_progress);
1265            if (percentage >= 2) {
1266                newtLabelSetText(g_timeline, timeline_str);
1267            }
1268            newtLabelSetText(g_percentline, percentline_str);
1269            newtRefresh();
1270        }
1271        paranoid_free(percentline_str);
1272        paranoid_free(timeline_str);
1273        paranoid_free(taskprogress);
1274        paranoid_free(tmp);
1275    }
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290/**
1291 * Ask the user which backup media type they would like to use.
1292 * The choices are @p none (exit to shell), @c cdr, @c cdrw, @c dvd,
1293 * @c tape, @c cdstream, @c udev (only when @p g_text_mode is TRUE), @c nfs,
1294 * and @c iso.
1295 * @param restoring TRUE if we're restoring, FALSE if we're backing up.
1296 * @return The backup type chosen, or @c none if the user chose "Exit to shell".
1297 */
1298    t_bkptype which_backup_media_type(bool restoring) {
1299
1300        /*@ char ************************************************************ */
1301        t_bkptype output;
1302
1303
1304        /*@ newt ************************************************************ */
1305        char *title_sz;
1306        char *minimsg_sz;
1307        static t_bkptype possible_bkptypes[] =
1308            { none, cdr, cdrw, dvd, tape, cdstream, udev, nfs, iso };
1309        static char *possible_responses[] =
1310            { "none", "cdr", "cdrw", "dvd", "tape", "cdstream", "udev",
1311"nfs", "iso", NULL };
1312        char *outstr;
1313        t_bkptype backup_type;
1314        int i;
1315
1316        newtComponent b1;
1317        newtComponent b2;
1318        newtComponent b3;
1319        newtComponent b4;
1320        newtComponent b5;
1321        newtComponent b6;
1322        newtComponent b7;
1323        newtComponent b8;
1324        newtComponent b_res;
1325        newtComponent myForm;
1326
1327        title_sz = malloc(MAX_NEWT_COMMENT_LEN);
1328        minimsg_sz = malloc(MAX_NEWT_COMMENT_LEN);
1329        outstr = malloc(MAX_NEWT_COMMENT_LEN);
1330        if (g_text_mode) {
1331            for (backup_type = none; backup_type == none;) {
1332                printf("Backup type (");
1333                for (i = 0; possible_responses[i]; i++) {
1334                    printf("%c%s", (i == 0) ? '\0' : ' ',
1335                           possible_responses[i]);
1336                }
1337                printf(")\n--> ");
1338                (void) fgets(outstr, MAX_NEWT_COMMENT_LEN, stdin);
1339                strip_spaces(outstr);
1340                for (i = 0; possible_responses[i]; i++) {
1341                    if (!strcmp(possible_responses[i], outstr)) {
1342                        backup_type = possible_bkptypes[i];
1343                    }
1344                }
1345            }
1346            paranoid_free(title_sz);
1347            paranoid_free(minimsg_sz);
1348            paranoid_free(outstr);
1349            return (backup_type);
1350        }
1351        newtDrawRootText(18, 0, WELCOME_STRING);
1352        if (restoring) {
1353            strcpy(title_sz,
1354                   "Please choose the backup media from which you want to read data.");
1355            strcpy(minimsg_sz, "Read from:");
1356        } else {
1357            strcpy(title_sz,
1358                   "Please choose the backup media to which you want to archive data.");
1359            strcpy(minimsg_sz, "Backup to:");
1360        }
1361        newtPushHelpLine(title_sz);
1362        //  newtOpenWindow (23, 3, 34, 17, minimsg_sz);
1363        newtCenteredWindow(34, 17, minimsg_sz);
1364        b1 = newtButton(1, 1, "CD-R disks ");
1365        b2 = newtButton(17, 1, "CD-RW disks");
1366        b3 = newtButton(1, 9, "Tape drive ");
1367        b4 = newtButton(17, 5, "CD streamer");
1368        b5 = newtButton(1, 5, " DVD disks ");
1369        b6 = newtButton(17, 9, " NFS mount ");
1370        b7 = newtButton(1, 13, " Hard disk ");
1371        b8 = newtButton(17, 13, "    Exit   ");
1372        myForm = newtForm(NULL, NULL, 0);
1373        newtFormAddComponents(myForm, b1, b5, b3, b7, b2, b4, b6, b8,
1374                              NULL);
1375        b_res = newtRunForm(myForm);
1376        newtFormDestroy(myForm);
1377        newtPopWindow();
1378        if (b_res == b1) {
1379            output = cdr;
1380        } else if (b_res == b2) {
1381            output = cdrw;
1382        } else if (b_res == b3) {
1383            output = tape;
1384        } else if (b_res == b4) {
1385            output = cdstream;
1386        } else if (b_res == b5) {
1387            output = dvd;
1388        } else if (b_res == b6) {
1389            output = nfs;
1390        } else if (b_res == b7) {
1391            output = iso;
1392        } else {
1393            output = none;
1394        }
1395        newtPopHelpLine();
1396        paranoid_free(title_sz);
1397        paranoid_free(minimsg_sz);
1398        paranoid_free(outstr);
1399        return (output);
1400    }
1401
1402
1403
1404
1405/**
1406 * Ask the user how much compression they would like to use.
1407 * The choices are "None" (0), "Minimum" (1), "Average" (4), and "Maximum" (9).
1408 * @return The compression level (0-9) chosen, or -1 for "Exit".
1409 */
1410    int
1411     which_compression_level() {
1412
1413        /*@ char ************************************************************ */
1414        int output = none;
1415
1416
1417        /*@ newt ************************************************************ */
1418
1419        newtComponent b1;
1420        newtComponent b2;
1421        newtComponent b3;
1422        newtComponent b4;
1423        newtComponent b5;
1424        newtComponent b_res;
1425        newtComponent myForm;
1426
1427        newtDrawRootText(18, 0, WELCOME_STRING);
1428        newtPushHelpLine
1429            ("   Please specify the level of compression that you want.");
1430        //  newtOpenWindow (23, 3, 34, 13, "How much compression?");
1431        newtCenteredWindow(34, 13, "How much compression?");
1432        b1 = newtButton(4, 1, "Maximum");
1433        b2 = newtButton(18, 1, "Average");
1434        b3 = newtButton(4, 5, "Minumum");
1435        b4 = newtButton(18, 5, " None  ");
1436        b5 = newtButton(4, 9, "         Exit        ");
1437        myForm = newtForm(NULL, NULL, 0);
1438        newtFormAddComponents(myForm, b1, b3, b2, b4, b5, NULL);
1439        b_res = newtRunForm(myForm);
1440        newtFormDestroy(myForm);
1441        newtPopWindow();
1442        if (b_res == b1) {
1443            output = 9;
1444        } else if (b_res == b2) {
1445            output = 4;
1446        } else if (b_res == b3) {
1447            output = 1;
1448        } else if (b_res == b4) {
1449            output = 0;
1450        } else if (b_res == b5) {
1451            output = -1;
1452        }
1453        newtPopHelpLine();
1454        return (output);
1455    }
1456
1457
1458
1459
1460
1461/**
1462 * Load @p source_file (a list of files) into @p filelist. There can be no more than
1463 * @p ARBITRARY_MAXIMUM entries.
1464 * @param filelist The filelist structure to load @p source_file into.
1465 * @param source_file The file containing a list of filenames to load into @p filelist.
1466 */
1467    int load_filelist_into_array(struct s_filelist *filelist,
1468                                 char *source_file) {
1469        int i;
1470        bool done;
1471        char *tmp;
1472        FILE *fin;
1473        struct s_filelist_entry dummy_fle;
1474
1475        malloc_string(tmp);
1476        assert(filelist != NULL);
1477        assert_string_is_neither_NULL_nor_zerolength(source_file);
1478
1479        iamhere("entering");
1480        if (!(fin = fopen(source_file, "r"))) {
1481            log_OS_error(source_file);
1482            log_msg(2, "Can't open %s; therefore, cannot popup list",
1483                    source_file);
1484            paranoid_free(tmp);
1485            return (1);
1486        }
1487        log_msg(2, "Loading %s", source_file);
1488        for (filelist->entries = 0; filelist->entries <= ARBITRARY_MAXIMUM;
1489             filelist->entries++) {
1490          god_i_hate_gotos:
1491            if (feof(fin)) {
1492                break;
1493            }
1494            (void) fgets(tmp, MAX_NEWT_COMMENT_LEN, fin);
1495            i = (int) strlen(tmp);
1496            if (i < 2) {
1497                goto god_i_hate_gotos;
1498            }
1499            if (tmp[i - 1] < 32) {
1500                tmp[--i] = '\0';
1501            }
1502            if (i < 2) {
1503                goto god_i_hate_gotos;
1504            }
1505            if (!does_file_exist(tmp)) {
1506                goto god_i_hate_gotos;
1507            }
1508            filelist->el[filelist->entries].severity =
1509                severity_of_difference(tmp, NULL);
1510            strcpy(filelist->el[filelist->entries].filename, tmp);
1511            if (feof(fin)) {
1512                break;
1513            }
1514        }
1515        paranoid_fclose(fin);
1516        if (filelist->entries >= ARBITRARY_MAXIMUM) {
1517            log_to_screen("Arbitrary limits suck, man!");
1518            paranoid_free(tmp);
1519            return (1);
1520        }
1521        for (done = FALSE; !done;) {
1522            done = TRUE;
1523            for (i = 0; i < filelist->entries - 1; i++) {
1524//          if (strcmp(filelist->el[i].filename, filelist->el[i+1].filename) > 0)
1525                if (filelist->el[i].severity < filelist->el[i + 1].severity
1526                    || (filelist->el[i].severity ==
1527                        filelist->el[i + 1].severity
1528                        && strcmp(filelist->el[i].filename,
1529                                  filelist->el[i + 1].filename) > 0)) {
1530                    memcpy((void *) &dummy_fle,
1531                           (void *) &(filelist->el[i]),
1532                           sizeof(struct s_filelist_entry));
1533                    memcpy((void *) &(filelist->el[i]),
1534                           (void *) &(filelist->el[i + 1]),
1535                           sizeof(struct s_filelist_entry));
1536                    memcpy((void *) &(filelist->el[i + 1]),
1537                           (void *) &dummy_fle,
1538                           sizeof(struct s_filelist_entry));
1539                    log_msg(2, "Swapping %s and %s",
1540                            filelist->el[i].filename,
1541                            filelist->el[i + 1].filename);
1542                    done = FALSE;
1543                }
1544            }
1545        }
1546        paranoid_free(tmp);
1547        iamhere("leaving");
1548        return (0);
1549    }
1550
1551
1552
1553/**
1554 * Generate a pretty string based on @p flentry.
1555 * @param flentry The filelist entry to stringify.
1556 * @return The string form of @p flentry.
1557 * @note The returned value points to static storage that will be overwritten with each call.
1558 */
1559    char *filelist_entry_to_string(struct s_filelist_entry *flentry) {
1560        static char comment[100];
1561        char *tmp;
1562
1563        iamhere("entering");
1564        malloc_string(tmp);
1565        assert(flentry != NULL);
1566        if (flentry->severity == 0) {
1567            strcpy(tmp, "0   ");
1568        } else if (flentry->severity == 1) {
1569            strcpy(tmp, "low ");
1570        } else if (flentry->severity == 2) {
1571            strcpy(tmp, "med ");
1572        } else {
1573            strcpy(tmp, "high");
1574        }
1575        strcat(tmp, "  ");
1576        strncat(tmp, flentry->filename, 100);
1577        tmp[98] = '\0';
1578        strcpy(comment, tmp);
1579        paranoid_free(tmp);
1580        iamhere("leaving");
1581        return (comment);
1582    }
1583
1584
1585
1586
1587
1588/**
1589 * Pop up a list containing the filenames in @p source_file and the severity if they have changed since the
1590 * last backup. There can be no more than @p ARBITRARY_MAXIMUM files in @p source_file.
1591 * @param source_file The file containing a list of changed files.
1592 */
1593    void popup_changelist_from_file(char *source_file) {
1594        char *reason;
1595        newtComponent myForm;
1596        newtComponent bClose;
1597        newtComponent bSelect;
1598        newtComponent b_res;
1599        newtComponent fileListbox;
1600        newtComponent headerMsg;
1601
1602        /*@ ???? ************************************************************ */
1603        void *curr_choice;
1604        void *keylist[ARBITRARY_MAXIMUM];
1605
1606        /*@ int ************************************************************* */
1607        int i = 0;
1608        int currline = 0;
1609        int finished = FALSE;
1610        long lng = 0;
1611
1612        /*@ buffers ********************************************************* */
1613        char *tmp;
1614        char *differ_sz;
1615
1616        struct s_filelist *filelist;
1617        malloc_string(reason);
1618        tmp = malloc(5000);
1619        malloc_string(differ_sz);
1620        assert_string_is_neither_NULL_nor_zerolength(source_file);
1621        if (g_text_mode) {
1622            log_msg(2, "Text mode. Therefore, no popup list.");
1623            goto free_to_go;
1624        }
1625        log_msg(2, "Examining file %s", source_file);
1626
1627        lng = count_lines_in_file(source_file);
1628        if (lng < 1) {
1629            log_msg(2, "No lines in file. Therefore, no popup list.");
1630            paranoid_free(reason);
1631            goto free_to_go;
1632        } else if (lng >= ARBITRARY_MAXIMUM) {
1633            log_msg(2, "Too many files differ for me to list.");
1634            goto free_to_go;
1635        }
1636
1637        filelist = (struct s_filelist *) malloc(sizeof(struct s_filelist));
1638        fileListbox =
1639            newtListbox(2, 2, 12, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1640        newtListboxClear(fileListbox);
1641
1642        if (load_filelist_into_array(filelist, source_file)) {
1643            log_msg(2, "Can't open %s; therefore, cannot popup list",
1644                    source_file);
1645            paranoid_free(reason);
1646            return;
1647        }
1648        log_msg(2, "%d files loaded into filelist array",
1649                filelist->entries);
1650        for (i = 0; i < filelist->entries; i++) {
1651            keylist[i] = (void *) i;
1652            newtListboxAppendEntry(fileListbox,
1653                                   filelist_entry_to_string(&
1654                                                            (filelist->
1655                                                             el[i])),
1656                                   keylist[i]);
1657        }
1658        sprintf(differ_sz,
1659                "  %d files differ. Hit 'Select' to pick a file. Hit 'Close' to quit the list.",
1660                i);
1661        newtPushHelpLine(differ_sz);
1662        bClose = newtCompactButton(10, 15, " Close  ");
1663        bSelect = newtCompactButton(30, 15, " Select ");
1664        sprintf(tmp, "%-10s               %-20s", "Priority", "Filename");
1665        headerMsg = newtLabel(2, 1, tmp);
1666        newtOpenWindow(5, 4, 70, 16, "Non-matching files");
1667        myForm = newtForm(NULL, NULL, 0);
1668        newtFormAddComponents(myForm, headerMsg, fileListbox, bClose,
1669                              bSelect, NULL);
1670        while (!finished) {
1671            b_res = newtRunForm(myForm);
1672            if (b_res == bClose) {
1673                finished = TRUE;
1674            } else {
1675                curr_choice = newtListboxGetCurrent(fileListbox);
1676                for (i = 0;
1677                     i < filelist->entries && keylist[i] != curr_choice;
1678                     i++);
1679                if (i == filelist->entries && filelist->entries > 0) {
1680                    log_to_screen("I don't know what that button does!");
1681                } else {
1682                    currline = i;
1683                    if (filelist->entries > 0) {
1684                        severity_of_difference(filelist->el[currline].
1685                                               filename, reason);
1686                        sprintf(tmp, "%s --- %s",
1687                                filelist->el[currline].filename, reason);
1688                        popup_and_OK(tmp);
1689                    }
1690                }
1691            }
1692        }
1693        newtFormDestroy(myForm);
1694        newtPopWindow();
1695        newtPopHelpLine();
1696      free_to_go:
1697        paranoid_free(reason);
1698        paranoid_free(tmp);
1699        paranoid_free(differ_sz);
1700        return;
1701    }
1702
1703/* @} - end of guiGroup */
1704
1705
1706#if __cplusplus
1707}                               /* extern "C" */
1708#endif
1709
1710
1711void wait_until_software_raids_are_prepped(char *mdstat_file,
1712                                           int wait_for_percentage);
Note: See TracBrowser for help on using the repository browser.