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

Last change on this file since 1770 was 1770, checked in by bruno, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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