source: branches/2.2.9/mondo/src/mondorestore/mondo-rstr-tools.c @ 2230

Last change on this file since 2230 was 2230, checked in by bruno, 10 years ago
  • Simplify log_it calls when possible (with just a fixed string)
  • issue with truncate_to_drive_name reported by valgrind at restore time. Needs rewrite IMO
  • Property svn:keywords set to Id
File size: 74.0 KB
Line 
1/***************************************************************************
2$Id: mondo-rstr-tools.c 2230 2009-06-17 20:53:23Z bruno $
3***************************************************************************/
4
5#include <pthread.h>
6#include <linux/fd.h>
7#include "my-stuff.h"
8#include "mr_mem.h"
9#include "../common/mondostructures.h"
10#include "../common/libmondo.h"
11#include "mr-externs.h"
12#include "mondo-rstr-tools.h"
13
14/**
15 * The biggielist stub (appended to the directory where all.tar.gz was unpacked).
16 */
17#define BIGGIELIST_TXT_STUB "tmp/biggielist.txt"
18
19/**
20 * The filelist stub (appended to the directory where all.tar.gz was unpacked).
21 */
22#define FILELIST_FULL_STUB "tmp/filelist.full.gz"
23
24/**
25 * The mountlist stub (appended to the directory where all.tar.gz was unpacked).
26 */
27#define MOUNTLIST_FNAME_STUB "tmp/mountlist.txt"
28
29/**
30 * The mondo-restore.cfg stub (appended to the directory where all.tar.gz was unpacked).
31 */
32#define MONDO_CFG_FILE_STUB "tmp/mondo-restore.cfg"
33/**
34 * The i-want-my-lvm stub
35 */
36#define IWANTMYLVM_STUB "tmp/i-want-my-lvm"
37
38extern bool g_ISO_restore_mode; /* are we in Iso Mode? */
39extern bool g_I_have_just_nuked;
40/*
41extern char *g_tmpfs_mountpt;
42*/
43extern char *g_isodir_device;
44extern char *g_isodir_format;
45extern long g_current_progress, g_maximum_progress;
46extern char *g_biggielist_txt;  // where 'biggielist.txt' is stored, on ramdisk / tempdir;
47                  // biggielist.txt is the list of big files stored on the
48                  // backup media set in question
49extern char *g_filelist_full;   // filelist.full.gz is the list of all regular files
50                  // (excluding big files) stored on the backup media set
51extern char *g_biggielist_pot;  // list of big files which _could_ be restored, if the
52                  // user chooses them
53extern char *g_filelist_imagedevs;  // list of devices (e.g. /dev/hda1, /dev/sda5) which
54                     // were archived as images, not just /dev entries
55                     // ... e.g. NTFS, BeOS partitions
56extern char *g_imagedevs_restthese; // of the imagedevs listed in FILELIST_IMAGEDEVS,
57                      // restore only these
58extern char *g_mondo_cfg_file;  // where m*ndo-restore.cfg (the config file) is stored
59extern char *g_mountlist_fname; // where mountlist.txt (the mountlist file) is stored
60extern char *g_mondo_home;      // homedir of Mondo; usually /usr/local/share/mondo
61
62extern t_bkptype g_backup_media_type;
63
64extern int g_partition_table_locked_up;
65extern char *MONDO_LOGFILE;
66
67/* Reference to global bkpinfo */
68extern struct s_bkpinfo *bkpinfo;
69
70/* Should we use or not extended attributes and acl when restoring */
71char *g_getfattr = NULL;
72char *g_getfacl = NULL;
73
74extern void kill_anything_like_this(char *str);
75extern int skip_obdr(void);
76extern int set_tape_block_size_with_mt(long internal_tape_block_size);
77
78/**
79* @addtogroup restoreUtilityGroup
80* @{
81*/
82/**
83* Free the malloc()s for the filename variables.
84*/
85void free_MR_global_filenames(void)
86{
87paranoid_free(g_biggielist_txt);
88paranoid_free(g_filelist_full);
89paranoid_free(g_filelist_imagedevs);
90paranoid_free(g_imagedevs_restthese);
91paranoid_free(g_mondo_cfg_file);
92paranoid_free(g_mountlist_fname);
93paranoid_free(g_mondo_home);
94/*
95paranoid_free(g_tmpfs_mountpt);
96*/
97paranoid_free(g_isodir_device);
98paranoid_free(g_isodir_format);
99
100}
101
102
103
104/**
105* Ask the user which imagedevs from the list contained in @p infname should
106* actually be restored.
107* @param infname The file containing a list of all imagedevs.
108* @param outfname The location of the output file containing the imagedevs the user wanted to restore.
109* @ingroup restoreUtilityGroup
110*/
111void ask_about_these_imagedevs(char *infname, char *outfname)
112{
113FILE *fin;
114FILE *fout;
115/************************************************************************
116* allocate memory regions. test and set  -sab 16 feb 2003              *
117************************************************************************/
118char *incoming_ptr;
119char *question_ptr;
120
121char incoming[MAX_STR_LEN] = "\0";
122char question[MAX_STR_LEN];
123
124assert_string_is_neither_NULL_nor_zerolength(infname);
125assert_string_is_neither_NULL_nor_zerolength(outfname);
126
127incoming_ptr = malloc(sizeof(incoming));
128if (incoming_ptr == NULL) {
129fprintf(stderr, "Out of Memory\n");
130exit(EXIT_FAILURE);
131}
132
133question_ptr = malloc(sizeof(question));
134if (question_ptr == NULL) {
135fprintf(stderr, "Out of Memory\n");
136exit(EXIT_FAILURE);
137}
138
139memset(incoming_ptr, '\0', sizeof(incoming));
140memset(question_ptr, '\0', sizeof(question));
141
142
143
144if (!(fin = fopen(infname, "r"))) {
145fatal_error("Cannot openin infname");
146}
147if (!(fout = fopen(outfname, "w"))) {
148fatal_error("Cannot openin outfname");
149}
150for (fgets(incoming_ptr, MAX_STR_LEN, fin);
151 !feof(fin); fgets(incoming_ptr, MAX_STR_LEN, fin)) {
152strip_spaces(incoming_ptr);
153
154if (incoming[0] == '\0') {
155    continue;
156}
157
158sprintf(question_ptr,
159        "Should I restore the image of %s ?", incoming_ptr);
160
161if (ask_me_yes_or_no(question_ptr)) {
162    fprintf(fout, "%s\n", incoming_ptr);
163}
164}
165
166/*** free memory ***********/
167paranoid_free(incoming_ptr);
168incoming_ptr = NULL;
169paranoid_free(question_ptr);
170question_ptr = NULL;
171
172
173paranoid_fclose(fout);
174paranoid_fclose(fin);
175}
176
177/**************************************************************************
178*ASK_ABOUT_THESE_IMAGEDEVS                                               *
179**************************************************************************/
180
181
182
183
184
185
186
187
188/**
189* Extract @c mondo-restore.cfg and @c mountlist.txt from @p ramdisk_fname.
190* @param bkpinfo The backup information structure. @c tmpdir is the only field used.
191* @param ramdisk_fname The filename of the @b compressed ramdisk to look in.
192* @param output_cfg_file Where to put the configuration file extracted.
193* @param output_mountlist_file Where to put the mountlist file extracted.
194* @return 0 for success, nonzero for failure.
195* @ingroup restoreUtilityGroup
196*/
197
198/**
199* Keep trying to get mondo-restore.cfg from the archive, until the user gives up.
200*/
201void get_cfg_file_from_archive_or_bust()
202{
203while (get_cfg_file_from_archive()) {
204if (!ask_me_yes_or_no
205    ("Failed to find config file/archives. Choose another source?"))
206{
207    fatal_error("Could not find config file/archives. Aborting.");
208}
209interactively_obtain_media_parameters_from_user(FALSE);
210}
211}
212
213
214/**
215* Determine whether @p list_fname contains a line containing @p f.
216* @param f The line to search for.
217* @param list_fname The file to search in.
218* @param preamble Ignore this beginning part of @p f ("" to disable).
219* @return TRUE if it's in the list, FALSE if it's not.
220*/
221bool is_file_in_list(char *f, char *list_fname, char *preamble)
222{
223
224/** needs malloc **/
225char *command;
226char *file;
227char *tmp;
228int res;
229
230malloc_string(command);
231malloc_string(file);
232malloc_string(tmp);
233assert_string_is_neither_NULL_nor_zerolength(f);
234assert_string_is_neither_NULL_nor_zerolength(list_fname);
235assert(preamble != NULL);
236
237if (strncmp(preamble, f, strlen(preamble)) == 0) {
238strcpy(file, f + strlen(preamble));
239} else {
240strcpy(file, f);
241}
242if (file[0] == '/' && file[1] == '/') {
243strcpy(tmp, file);
244strcpy(file, tmp + 1);
245}
246sprintf(tmp,
247    "Checking to see if f=%s, file=%s, is in the list of biggiefiles",
248    f, file);
249log_msg(2, tmp);
250sprintf(command, "grep -E '^%s$' %s", file, list_fname);
251res = run_program_and_log_output(command, FALSE);
252paranoid_free(command);
253paranoid_free(file);
254paranoid_free(tmp);
255if (res) {
256return (FALSE);
257} else {
258return (TRUE);
259}
260}
261
262/**************************************************************************
263*END_IS_FILE_IN_LIST                                                     *
264**************************************************************************/
265
266
267
268/**
269* Set up an ISO backup.
270* @param bkpinfo The backup information structure. Fields used:
271* - @c bkpinfo->backup_media_type
272* - @c bkpinfo->disaster_recovery
273* - @c bkpinfo->isodir
274* @param nuke_me_please If TRUE, we're in nuke mode; if FALSE we're in interactive mode.
275* @return 0 for success, nonzero for failure.
276*/
277int iso_fiddly_bits(bool nuke_me_please)
278{
279char *mount_isodir_command = NULL;
280char *tmp, *command;
281int retval = 0, i;
282bool already_mounted = FALSE;
283
284assert(bkpinfo != NULL);
285malloc_string(tmp);
286malloc_string(command);
287g_ISO_restore_mode = TRUE;
288read_cfg_var(g_mondo_cfg_file, "iso-dev", g_isodir_device);
289if (bkpinfo->disaster_recovery) {
290    /* Patch Conor Daly 26-june-2004
291    * Don't let this clobber an existing bkpinfo->isodir */
292    if (!bkpinfo->isodir[0]) {
293        strcpy(bkpinfo->isodir, "/tmp/isodir");
294    }
295    /* End patch */
296    sprintf(command, "mkdir -p %s", bkpinfo->isodir);
297    run_program_and_log_output(command, 5);
298    log_msg(2, "Setting isodir to %s", bkpinfo->isodir);
299}
300
301if (!get_isodir_info(g_isodir_device, g_isodir_format, bkpinfo->isodir, nuke_me_please)) {
302    return (1);
303}
304paranoid_system("umount " MNT_CDROM " 2> /dev/null");   /* just in case */
305
306if (is_this_device_mounted(g_isodir_device)) {
307    log_to_screen("WARNING - isodir is already mounted");
308    already_mounted = TRUE;
309} else {
310    mr_asprintf(&mount_isodir_command, "mount %s", g_isodir_device);
311    if (strlen(g_isodir_format) > 1) {
312        mr_strcat(mount_isodir_command, " -t %s", g_isodir_format);
313    }
314    mr_strcat(mount_isodir_command, " -o ro %s", bkpinfo->isodir);
315    run_program_and_log_output("df -m", FALSE);
316    sprintf(tmp,
317        "The 'mount' command is '%s'. PLEASE report this command to be if you have problems, ok?",
318        mount_isodir_command);
319    log_msg(1, tmp);
320    if (run_program_and_log_output(mount_isodir_command, FALSE)) {
321        popup_and_OK
322            ("Cannot mount the device where the ISO files are stored.");
323        return (1);
324    }
325    paranoid_free(mount_isodir_command);
326    log_to_screen
327    ("I have mounted the device where the ISO files are stored.");
328}
329if (!IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
330    mount_media();
331}
332i = what_number_cd_is_this();   /* has the side-effect of calling mount_media() */
333sprintf(tmp, "%s #%d has been mounted via loopback mount",
334    media_descriptor_string(bkpinfo->backup_media_type), i);
335log_msg(1, tmp);
336if (i < 0) {
337popup_and_OK
338    ("Cannot find ISO images in the directory you specified.");
339retval = 1;
340}
341log_msg(2, "%ld: bkpinfo->isodir is now %s", __LINE__,
342    bkpinfo->isodir);
343paranoid_free(tmp);
344paranoid_free(command);
345return (retval);
346}
347
348
349
350
351/**
352* Kill all Petris processes.
353*/
354void kill_petris(void) {
355    kill_anything_like_this("petris");
356}
357
358/**************************************************************************
359*END_KILL_PETRIS                                                         *
360**************************************************************************/
361
362
363/**
364 * Mount @p device at @p mpt as @p format.
365 * @param device The device (/dev entry) to mount.
366 * @param mpt The directory to mount it on.
367 * @param format The filesystem type of @p device.
368 * @param writeable If TRUE, mount read-write; if FALSE, mount read-only.
369 * @return 0 for success, nonzero for failure.
370 */
371int mount_device(char *device, char *mpt, char *format, bool writeable)
372{
373int res = 0;
374
375/** malloc **/
376char *tmp, *command, *mountdir, *mountpoint;
377char *additional_parameters = NULL;
378
379assert_string_is_neither_NULL_nor_zerolength(device);
380assert_string_is_neither_NULL_nor_zerolength(mpt);
381assert(format != NULL);
382malloc_string(tmp);
383malloc_string(command);
384malloc_string(mountdir);
385malloc_string(mountpoint);
386
387    if (!strcmp(mpt, "/1")) {
388        strcpy(mountpoint, "/");
389        log_msg(3, "Mommm! SME is being a dildo!");
390    } else {
391        strcpy(mountpoint, mpt);
392    }
393
394    if (!strcmp(mountpoint, "lvm")) {
395        return (0);
396    }
397    if (!strcmp(mountpoint, "image")) {
398        return (0);
399    }
400    sprintf(tmp, "Mounting device %s   ", device);
401    log_msg(1, tmp);
402    /* Deal with additional params only if not /proc or /sys */
403    mr_asprintf(&additional_parameters, "");
404    if (strcmp(format, "proc") && strcmp(format, "sys")) {
405        if (writeable) {
406            mr_strcat(additional_parameters, "-o rw");
407        } else {
408            mr_strcat(additional_parameters, "-o ro");
409        }
410        if (find_home_of_exe("setfattr")) {
411            mr_strcat(additional_parameters, ",user_xattr");
412        }
413        if (find_home_of_exe("setfacl")) {
414            mr_strcat(additional_parameters, ",acl");
415        }
416    }
417
418    if (!strcmp(mountpoint, "swap")) {
419        sprintf(command, "swapon %s", device);
420    } else {
421        if (!strcmp(mountpoint, "/")) {
422            strcpy(mountdir, MNT_RESTORING);
423        } else {
424            sprintf(mountdir, "%s%s", MNT_RESTORING, mountpoint);
425        }
426        sprintf(command, "mkdir -p %s", mountdir);
427        run_program_and_log_output(command, FALSE);
428        sprintf(command, "mount -t %s %s %s %s 2>> %s", format, device,
429                additional_parameters, mountdir, MONDO_LOGFILE);
430        log_msg(2, "command='%s'", command);
431    }
432    paranoid_free(additional_parameters);
433
434    res = run_program_and_log_output(command, TRUE);
435    if (res && (strstr(command, "xattr") || strstr(command, "acl"))) {
436        log_msg(1, "Re-trying without the fancy extra parameters");
437        sprintf(command, "mount -t %s %s %s 2>> %s", format, device,
438            mountdir, MONDO_LOGFILE);
439        res = run_program_and_log_output(command, TRUE);
440    }
441    if (res) {
442        log_msg(1, "Unable to mount device %s (type %s) at %s", device,
443                format, mountdir);
444        log_msg(1, "command was '%s'", command);
445        if (!strcmp(mountpoint, "swap")) {
446            log_to_screen(tmp);
447        } else {
448            log_msg(2, "Retrying w/o the '-t' switch");
449            sprintf(command, "mount %s %s 2>> %s", device, mountdir,
450                MONDO_LOGFILE);
451            log_msg(2, "2nd command = '%s'", command);
452            res = run_program_and_log_output(command, TRUE);
453            if (res == 0) {
454                log_msg(1,
455                    "That's OK. I called mount w/o a filesystem type and it worked fine in the end.");
456            } else {
457                log_to_screen(tmp);
458            }
459        }
460    }
461
462    if (res && !strcmp(mountpoint, "swap")) {
463        log_msg(2, "That's ok. It's just a swap partition.");
464        log_msg(2, "Non-fatal error. Returning 0.");
465        res = 0;
466    }
467
468paranoid_free(tmp);
469paranoid_free(command);
470paranoid_free(mountdir);
471paranoid_free(mountpoint);
472
473    return (res);
474}
475/**************************************************************************
476 *END_MOUNT_DEVICE                                                        *
477**************************************************************************/
478
479
480/**
481 * Mount all devices in @p p_external_copy_of_mountlist on @p MNT_RESTORING.
482 * @param p_external_copy_of_mountlist The mountlist containing devices to be mounted.
483 * @param writeable If TRUE, then mount read-write; if FALSE mount read-only.
484 * @return The number of errors encountered (0 for success).
485 */
486int mount_all_devices(struct mountlist_itself
487                      *p_external_copy_of_mountlist, bool writeable)
488{
489int retval = 0, lino, res;
490char *tmp;
491char *these_failed = NULL;
492char *format;
493struct mountlist_itself *mountlist = NULL;
494
495malloc_string(tmp);
496malloc_string(format);
497
498assert(p_external_copy_of_mountlist != NULL);
499mountlist = malloc(sizeof(struct mountlist_itself));
500memcpy((void *) mountlist, (void *) p_external_copy_of_mountlist,
501   sizeof(struct mountlist_itself));
502    sort_mountlist_by_mountpoint(mountlist, 0);
503
504
505    mvaddstr_and_log_it(g_currentY, 0, "Mounting devices         ");
506    open_progress_form("Mounting devices",
507               "I am now mounting all the drives.",
508               "This should not take long.",
509               "", mountlist->entries);
510
511    mr_asprintf(&these_failed, "");
512    for (lino = 0; lino < mountlist->entries; lino++) {
513        if (!strcmp(mountlist->el[lino].device, "/proc")) {
514            log_msg(1,
515                "Again with the /proc - why is this in your mountlist?");
516        } else if (is_this_device_mounted(mountlist->el[lino].device)) {
517            sprintf(tmp, "%s is already mounted",
518                mountlist->el[lino].device);
519            log_to_screen(tmp);
520        } else if (strcmp(mountlist->el[lino].mountpoint, "none")
521           && strcmp(mountlist->el[lino].mountpoint, "lvm")
522           && strcmp(mountlist->el[lino].mountpoint, "raid")
523           && strcmp(mountlist->el[lino].mountpoint, "image")) {
524            sprintf(tmp, "Mounting %s", mountlist->el[lino].device);
525            update_progress_form(tmp);
526            strcpy(format, mountlist->el[lino].format);
527            res = mount_device(mountlist->el[lino].device,
528                       mountlist->el[lino].mountpoint,
529                       format, writeable);
530            retval += res;
531            if (res) {
532                mr_strcat(these_failed, "%s ",mountlist->el[lino].device);
533            }
534        }
535        g_current_progress++;
536    }
537    close_progress_form();
538    if (retval) {
539        if (g_partition_table_locked_up > 0) {
540            log_to_screen
541                ("fdisk's ictol() call to refresh its copy of the partition table causes the kernel to");
542            log_to_screen
543                ("lock up the partition table. You might have to reboot and use Interactive Mode to");
544            log_to_screen
545                ("format and restore *without* partitioning first. Sorry for the inconvenience.");
546        }
547        sprintf(tmp, "Could not mount device(s) %s- shall I abort?", these_failed);
548
549        if (!ask_me_yes_or_no(tmp)) {
550            retval = 0;
551            log_to_screen
552                ("Continuing, although some device(s) failed to be mounted");
553            mvaddstr_and_log_it(g_currentY++, 74, "Done.");
554        } else {
555            mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
556            log_to_screen
557        ("Unable to mount some or all of your partitions.");
558        }
559    } else {
560        log_to_screen("All partitions were mounted OK.");
561        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
562    }
563    paranoid_free(these_failed);
564
565    /* Also mounting under MNT_RESTORING  special FS */
566    (void)mount_device("/proc","/proc","proc",TRUE);
567    (void)mount_device("/sys","/sys","sysfs",TRUE);
568    run_program_and_log_output("df -m", 3);
569    paranoid_free(mountlist);
570    paranoid_free(tmp);
571    paranoid_free(format);
572    return (retval);
573}
574/**************************************************************************
575*END_MOUNT_ALL_DEVICES                                                   *
576**************************************************************************/
577
578
579/**
580* Mount the CD-ROM or USB device at /mnt/cdrom.
581* @param bkpinfo The backup information structure. Fields used:
582* - @c bkpinfo->backup_media_type
583* - @c bkpinfo->disaster_recovery
584* - @c bkpinfo->isodir
585* - @c bkpinfo->media_device
586* @return 0 for success, nonzero for failure.
587*/
588int mount_media()
589{
590char *mount_cmd;
591int i, res;
592#ifdef __FreeBSD__
593char mdd[32];
594char *mddev = mdd;
595#endif
596
597malloc_string(mount_cmd);
598assert(bkpinfo != NULL);
599
600    if (bkpinfo->backup_media_type == tape
601        || bkpinfo->backup_media_type == udev) {
602        log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
603        paranoid_free(mount_cmd);
604        return 0;
605    }
606
607    if (!run_program_and_log_output("mount | grep -F " MNT_CDROM, FALSE)) {
608        log_msg(2, "mount_media() - media already mounted. Fair enough.");
609        paranoid_free(mount_cmd);
610        return (0);
611    }
612
613    if (bkpinfo->backup_media_type == nfs) {
614        log_msg(2, "Mounting for NFS thingy");
615        log_msg(2, "isodir = %s", bkpinfo->isodir);
616        if ((!bkpinfo->isodir[0] || !strcmp(bkpinfo->isodir, "/"))
617            && am_I_in_disaster_recovery_mode()) {
618            strcpy(bkpinfo->isodir, "/tmp/isodir");
619            log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
620        }
621#ifdef __FreeBSD__
622        sprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir,
623            bkpinfo->nfs_remote_dir, bkpinfo->prefix, g_current_media_number);
624        mddev = make_vn(mount_cmd);
625        sprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev);
626#else
627        sprintf(mount_cmd, "mount %s/%s/%s-%d.iso -t iso9660 -o loop,ro %s",
628            bkpinfo->isodir, bkpinfo->nfs_remote_dir,
629            bkpinfo->prefix, g_current_media_number, MNT_CDROM);
630#endif
631
632    } else if (bkpinfo->backup_media_type == iso) {
633#ifdef __FreeBSD__
634        sprintf(mount_cmd, "%s/%s-%d.iso", bkpinfo->isodir,
635            bkpinfo->prefix, g_current_media_number);
636        mddev = make_vn(mount_cmd);
637        sprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM);
638#else
639        sprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s",
640            bkpinfo->isodir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
641#endif
642    } else if (bkpinfo->backup_media_type == usb) {
643        sprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM);
644    } else if (strstr(bkpinfo->media_device, "/dev/")) {
645#ifdef __FreeBSD__
646        sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
647        MNT_CDROM);
648#else
649        sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
650        bkpinfo->media_device, MNT_CDROM);
651#endif
652    } else {
653        if (bkpinfo->disaster_recovery
654            && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
655            strcpy(bkpinfo->media_device,
656                last_line_of_file("/tmp/CDROM-LIVES-HERE"));
657        } else {
658            find_cdrom_device(bkpinfo->media_device, TRUE);
659        }
660
661#ifdef __FreeBSD__
662    sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
663        MNT_CDROM);
664#else
665    sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
666        bkpinfo->media_device, MNT_CDROM);
667#endif
668    }
669
670    log_msg(2, "(mount_media) --- command = %s", mount_cmd);
671    for (i = 0; i < 2; i++) {
672        res = run_program_and_log_output(mount_cmd, FALSE);
673        if (!res) {
674            break;
675        } else {
676            log_msg(2, "Failed to mount device.");
677            sleep(5);
678            run_program_and_log_output("sync", FALSE);
679        }
680    }
681
682    if (res) {
683        log_msg(2, "Failed, despite %d attempts", i);
684    } else {
685        log_msg(2, "Mounted media drive OK");
686    }
687    paranoid_free(mount_cmd);
688    return (res);
689}
690/**************************************************************************
691*END_MOUNT_CDROM                                                         *
692**************************************************************************/
693
694
695
696/**
697* Fix some miscellaneous things in the filesystem so the system will come
698* up correctly on the first boot.
699*/
700void protect_against_braindead_sysadmins()
701{
702run_program_and_log_output("touch " MNT_RESTORING "/var/log/pacct",
703                       FALSE);
704run_program_and_log_output("touch " MNT_RESTORING "/var/account/pacct",
705                       FALSE);
706if (run_program_and_log_output("ls " MNT_RESTORING " /tmp", FALSE)) {
707run_program_and_log_output("chmod 1777 " MNT_RESTORING "/tmp",
708                           FALSE);
709}
710run_program_and_log_output("mkdir -p " MNT_RESTORING
711                       "/var/run/console", FALSE);
712run_program_and_log_output("chmod 777 " MNT_RESTORING "/dev/null",
713                       FALSE);
714run_program_and_log_output("cd " MNT_RESTORING
715                       "; for i in `ls home/`; do echo \"Moving $i's spurious files to $i/.disabled\"; mkdir \"$i\"/.disabled ; mv -f \"$i\"/.DCOP* \"$i\"/.MCOP* \"$i\"/.*authority \"$i\"/.kde/tmp* \"$i\"/.kde/socket* \"$i\"/.disabled/ ; done",
716                       TRUE);
717run_program_and_log_output("rm -f " MNT_RESTORING "/var/run/*.pid",
718                       TRUE);
719run_program_and_log_output("rm -f " MNT_RESTORING "/var/lock/subsys/*",
720                       TRUE);
721}
722
723/**************************************************************************
724*END_PROTECT_AGAINST_BRAINDEAD_SYSADMINS                                 *
725**************************************************************************/
726
727
728
729
730/**
731* Fill out @p bkpinfo based on @p cfg_file.
732* @param cfg_file The mondo-restore.cfg file to read into @p bkpinfo.
733* @param bkpinfo The backup information structure to fill out with information
734* from @p cfg_file.
735* @return 0 for success, nonzero for failure.
736*/
737int read_cfg_file_into_bkpinfo(char *cfgf)
738{
739/** add mallocs **/
740char *value = NULL;
741char *tmp = NULL;
742char *envtmp1 = NULL;
743char *envtmp2 = NULL;
744char *command = NULL;
745char *iso_mnt = NULL;
746char *iso_path = NULL;
747char *old_isodir = NULL;
748char cfg_file[100];
749t_bkptype media_specified_by_user;
750
751malloc_string(command);
752malloc_string(iso_mnt);
753malloc_string(iso_path);
754malloc_string(old_isodir);
755malloc_string(value);
756malloc_string(tmp);
757//  assert_string_is_neither_NULL_nor_zerolength(cfg_file);
758assert(bkpinfo != NULL);
759
760if (!cfgf) {
761    strcpy(cfg_file, g_mondo_cfg_file);
762} else {
763    strcpy(cfg_file, cfgf);
764}
765
766media_specified_by_user = bkpinfo->backup_media_type;   // or 'none', if not specified
767
768if (0 == read_cfg_var(cfg_file, "backup-media-type", value)) {
769if (!strcmp(value, "cdstream")) {
770    bkpinfo->backup_media_type = cdstream;
771} else if (!strcmp(value, "cdr")) {
772    bkpinfo->backup_media_type = cdr;
773} else if (!strcmp(value, "cdrw")) {
774    bkpinfo->backup_media_type = cdrw;
775} else if (!strcmp(value, "dvd")) {
776    bkpinfo->backup_media_type = dvd;
777} else if (!strcmp(value, "usb")) {
778    bkpinfo->backup_media_type = usb;
779    bkpinfo->please_dont_eject = TRUE;
780} else if (!strcmp(value, "iso")) {
781
782// Patch by Conor Daly - 2004/07/12
783    bkpinfo->backup_media_type = iso;
784    if (am_I_in_disaster_recovery_mode()) {
785        /* Check to see if CD is already mounted before mounting it... */
786        if (!is_this_device_mounted("/dev/cdrom")) {
787            log_msg(2,
788                    "NB: CDROM device not mounted, mounting...");
789            run_program_and_log_output("mount /dev/cdrom "
790                                       MNT_CDROM, 1);
791        }
792        if (does_file_exist(MNT_CDROM "/archives/filelist.0")) {
793            bkpinfo->backup_media_type = cdr;
794            run_program_and_log_output("umount " MNT_CDROM, 1);
795            log_it
796                ("Re-jigging configuration AGAIN. CD-R, not ISO.");
797        }
798    }
799    if (read_cfg_var(cfg_file, "iso-prefix", value) == 0) {
800            strcpy(bkpinfo->prefix,value);
801    } else {
802            strcpy(bkpinfo->prefix,STD_PREFIX);
803    }
804} else if (!strcmp(value, "nfs")) {
805    bkpinfo->backup_media_type = nfs;
806    bkpinfo->please_dont_eject = TRUE;
807    if (read_cfg_var(cfg_file, "iso-prefix", value) == 0) {
808            strcpy(bkpinfo->prefix,value);
809    } else {
810            strcpy(bkpinfo->prefix,STD_PREFIX);
811    }
812    if (strstr(call_program_and_get_last_line_of_output
813       ("cat /proc/cmdline"), "pxe")) {
814        /* We need to override prefix value in PXE mode as it's
815        * already done in start-nfs */
816        envtmp1 = getenv("imgname");
817        if (envtmp1 == NULL) {
818            fatal_error("no imgname variable in environment");
819        }
820        strcpy(bkpinfo->prefix,envtmp1);
821    }
822
823} else if (!strcmp(value, "tape")) {
824    bkpinfo->backup_media_type = tape;
825} else if (!strcmp(value, "udev")) {
826    bkpinfo->backup_media_type = udev;
827} else {
828    fatal_error("UNKNOWN bkp-media-type");
829}
830} else {
831fatal_error("backup-media-type not specified!");
832}
833if (bkpinfo->disaster_recovery) {
834    if (bkpinfo->backup_media_type == cdstream) {
835        sprintf(bkpinfo->media_device, "/dev/cdrom");
836//          bkpinfo->media_size[0] = -1;
837        bkpinfo->media_size[0] = 1999 * 1024;
838        bkpinfo->media_size[1] = 650;   /* good guess */
839    } else if (bkpinfo->backup_media_type == usb) {
840        envtmp1 = getenv("MRUSBDEV");
841        if (envtmp1 == NULL) {
842            if (read_cfg_var(cfg_file, "usb-dev", value)) {
843                fatal_error("Cannot get USB device name from cfg file");
844            }
845        } else {
846            strcpy(value,envtmp1);
847        }
848        sprintf(bkpinfo->media_device, "%s1", value);
849        sprintf(tmp, "Backup medium is USB --- dev=%s", bkpinfo->media_device);
850        log_msg(2, tmp);
851    } else if (bkpinfo->backup_media_type == tape
852            || bkpinfo->backup_media_type == udev) {
853        if (read_cfg_var(cfg_file, "media-dev", value)) {
854            fatal_error("Cannot get tape device name from cfg file");
855        }
856        strcpy(bkpinfo->media_device, value);
857        read_cfg_var(cfg_file, "media-size", value);
858        bkpinfo->media_size[1] = atol(value);
859        sprintf(tmp, "Backup medium is TAPE --- dev=%s",
860                bkpinfo->media_device);
861        log_msg(2, tmp);
862    } else {
863        strcpy(bkpinfo->media_device, "/dev/cdrom");    /* we don't really need this var */
864        bkpinfo->media_size[0] = 1999 * 1024;   /* 650, probably, but we don't need this var anyway */
865        bkpinfo->media_size[1] = 1999 * 1024;   /* 650, probably, but we don't need this var anyway */
866        log_msg(2, "Backup medium is CD-R[W]");
867    }
868} else {
869    log_msg(2,
870        "Not in Disaster Recovery Mode. No need to derive device name from config file.");
871}
872
873read_cfg_var(cfg_file, "use-star", value);
874if (strstr(value, "yes")) {
875    bkpinfo->use_star = TRUE;
876    log_msg(1, "Goody! ... bkpinfo->use_star is now true.");
877}
878
879read_cfg_var(cfg_file, "obdr", value);
880if (strstr(value, "TRUE")) {
881    bkpinfo->use_obdr = TRUE;
882    log_msg(1, "OBDR mode activated");
883}
884
885read_cfg_var(cfg_file, "acl", value);
886if (strstr(value, "TRUE")) {
887    mr_asprintf(&g_getfacl,"setfacl");
888    log_msg(1, "We will restore ACLs");
889    if (! find_home_of_exe("setfacl")) {
890        log_msg(1, "Unable to restore ACLs as no setfacl found");
891    }
892}
893read_cfg_var(cfg_file, "xattr", value);
894if (strstr(value, "TRUE")) {
895    mr_asprintf(&g_getfattr,"setfattr");
896    log_msg(1, "We will restore XATTRs");
897    if (! find_home_of_exe("setfattr")) {
898        log_msg(1, "Unable to restore XATTRs as no setfattr found");
899    }
900}
901
902if (0 == read_cfg_var(cfg_file, "internal-tape-block-size", value)) {
903bkpinfo->internal_tape_block_size = atol(value);
904log_msg(1, "Internal tape block size has been custom-set to %ld",
905        bkpinfo->internal_tape_block_size);
906} else {
907bkpinfo->internal_tape_block_size =
908    DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
909log_msg(1, "Internal tape block size = default (%ld)",
910        DEFAULT_INTERNAL_TAPE_BLOCK_SIZE);
911}
912
913read_cfg_var(cfg_file, "use-lzo", value);
914if (strstr(value, "yes")) {
915bkpinfo->use_lzo = TRUE;
916bkpinfo->use_gzip = FALSE;
917strcpy(bkpinfo->zip_exe, "lzop");
918strcpy(bkpinfo->zip_suffix, "lzo");
919} else {
920read_cfg_var(cfg_file, "use-gzip", value);
921if (strstr(value, "yes")) {
922    bkpinfo->use_lzo = FALSE;
923    bkpinfo->use_gzip = TRUE;
924    strcpy(bkpinfo->zip_exe, "gzip");
925    strcpy(bkpinfo->zip_suffix, "gz");
926} else {
927    read_cfg_var(cfg_file, "use-comp", value);
928    if (strstr(value, "yes")) {
929        bkpinfo->use_lzo = FALSE;
930        bkpinfo->use_gzip = FALSE;
931        strcpy(bkpinfo->zip_exe, "bzip2");
932        strcpy(bkpinfo->zip_suffix, "bz2");
933    } else {
934        bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
935    }
936}
937}
938
939value[0] = '\0';
940read_cfg_var(cfg_file, "differential", value);
941if (!strcmp(value, "yes") || !strcmp(value, "1")) {
942bkpinfo->differential = TRUE;
943}
944log_msg(2, "differential var = '%s'", value);
945if (bkpinfo->differential) {
946log_msg(2, "THIS IS A DIFFERENTIAL BACKUP");
947} else {
948log_msg(2, "This is a regular (full) backup");
949}
950
951read_cfg_var(g_mondo_cfg_file, "please-dont-eject", tmp);
952if (tmp[0]
953||
954strstr(call_program_and_get_last_line_of_output
955       ("cat /proc/cmdline"), "donteject")) {
956bkpinfo->please_dont_eject = TRUE;
957log_msg(2, "Ok, I shan't eject when restoring! Groovy.");
958}
959
960if (bkpinfo->backup_media_type == nfs) {
961    if (!cfgf) {
962        log_msg(2, "nfs_mount remains %s", bkpinfo->nfs_mount);
963        log_msg(2, "nfs_remote_dir remains %s",
964                bkpinfo->nfs_remote_dir);
965        log_msg(2,
966                "...cos it wouldn't make sense to abandon the values that GOT ME to this config file in the first place");
967    } else {
968        read_cfg_var(g_mondo_cfg_file, "nfs-server-mount",
969                    bkpinfo->nfs_mount);
970        read_cfg_var(g_mondo_cfg_file, "nfs-server-path",
971                    bkpinfo->nfs_remote_dir);
972        log_msg(2, "nfs_mount is %s", bkpinfo->nfs_mount);
973        log_msg(2, "nfs_remote_dir is %s", bkpinfo->nfs_remote_dir);
974    }
975    if (strstr(call_program_and_get_last_line_of_output
976        ("cat /proc/cmdline"), "pxe")) {
977        /* We need to override values in PXE mode as it's
978        * already done in start-nfs */
979        envtmp1 = getenv("nfsmount");
980        if (envtmp1 == NULL) {
981            fatal_error("no nfsmount variable in environment");
982        }
983        envtmp2 = getenv("dirimg");
984        if (envtmp2 == NULL) {
985            fatal_error("no dirimg variable in environment");
986        }
987        strcpy(bkpinfo->nfs_mount,envtmp1);
988        strcpy(bkpinfo->nfs_remote_dir,envtmp2);
989    }
990} else if (bkpinfo->backup_media_type == iso) {
991    /* Patch by Conor Daly 23-june-2004
992    * to correctly mount iso-dev and set a sensible
993    * isodir in disaster recovery mode
994    */
995    strcpy(old_isodir, bkpinfo->isodir);
996    read_cfg_var(g_mondo_cfg_file, "iso-mnt", iso_mnt);
997    read_cfg_var(g_mondo_cfg_file, "isodir", iso_path);
998    sprintf(bkpinfo->isodir, "%s%s", iso_mnt, iso_path);
999    if (!bkpinfo->isodir[0]) {
1000        strcpy(bkpinfo->isodir, old_isodir);
1001    }
1002    if (!bkpinfo->disaster_recovery) {
1003        if (strcmp(old_isodir, bkpinfo->isodir)) {
1004            log_it
1005                ("user nominated isodir differs from archive, keeping user's choice: %s %s\n",
1006                old_isodir, bkpinfo->isodir);
1007            strcpy(bkpinfo->isodir, old_isodir);
1008        }
1009    }
1010    read_cfg_var(g_mondo_cfg_file, "iso-dev", g_isodir_device);
1011    log_msg(2, "isodir=%s; iso-dev=%s", bkpinfo->isodir,
1012            g_isodir_device);
1013    if (bkpinfo->disaster_recovery) {
1014        if (is_this_device_mounted(g_isodir_device)) {
1015            log_msg(2, "NB: isodir is already mounted");
1016            /* Find out where it's mounted */
1017            sprintf(command,
1018                    "mount | grep -E '^%s' | tail -n1 | cut -d' ' -f3",
1019                    g_isodir_device);
1020            log_it("command = %s", command);
1021            log_it("res of it = %s",
1022                call_program_and_get_last_line_of_output(command));
1023            sprintf(iso_mnt, "%s",
1024                    call_program_and_get_last_line_of_output(command));
1025        } else {
1026            sprintf(iso_mnt, "/tmp/isodir");
1027            sprintf(tmp, "mkdir -p %s", iso_mnt);
1028            run_program_and_log_output(tmp, 5);
1029            sprintf(tmp, "mount %s %s", g_isodir_device, iso_mnt);
1030            if (run_program_and_log_output(tmp, 3)) {
1031                log_msg(1,
1032                        "Unable to mount isodir. Perhaps this is really a CD backup?");
1033                bkpinfo->backup_media_type = cdr;
1034                strcpy(bkpinfo->media_device, "/dev/cdrom");    /* superfluous */
1035                bkpinfo->isodir[0] = iso_mnt[0] = iso_path[0] = '\0';
1036                if (mount_media()) {
1037                    fatal_error
1038                        ("Unable to mount isodir. Failed to mount CD-ROM as well.");
1039                } else {
1040                    log_msg(1,
1041                            "You backed up to disk, then burned some CDs.");
1042                }
1043            }
1044        }
1045        /* bkpinfo->isodir should now be the true path to prefix-1.iso etc... */
1046        if (bkpinfo->backup_media_type == iso) {
1047            sprintf(bkpinfo->isodir, "%s%s", iso_mnt, iso_path);
1048        }
1049    }
1050}
1051
1052if (media_specified_by_user != none) {
1053    if (g_restoring_live_from_cd) {
1054        if (bkpinfo->backup_media_type != media_specified_by_user) {
1055            log_msg(2,
1056                    "bkpinfo->backup_media_type != media_specified_by_user, so I'd better ask :)");
1057            interactively_obtain_media_parameters_from_user(FALSE);
1058            media_specified_by_user = bkpinfo->backup_media_type;
1059            get_cfg_file_from_archive();
1060    /*
1061        if (media_specified_by_user != cdr && media_specified_by_user == cdrw)
1062            { g_restoring_live_from_cd = FALSE; }
1063    */
1064        }
1065    }
1066    bkpinfo->backup_media_type = media_specified_by_user;
1067}
1068g_backup_media_type = bkpinfo->backup_media_type;
1069paranoid_free(value);
1070paranoid_free(tmp);
1071paranoid_free(command);
1072paranoid_free(iso_mnt);
1073paranoid_free(iso_path);
1074paranoid_free(old_isodir);
1075return (0);
1076
1077}
1078
1079/**************************************************************************
1080*END_READ_CFG_FILE_INTO_BKPINFO                                          *
1081**************************************************************************/
1082
1083
1084
1085
1086/**
1087 * Allow the user to edit the filelist and biggielist.
1088 * The filelist is unlinked after it is read.
1089 * @param bkpinfo The backup information structure. Fields used:
1090 * - @c bkpinfo->backup_media_type
1091 * - @c bkpinfo->isodir
1092 * - @c bkpinfo->media_device
1093 * - @c bkpinfo->tmpdir
1094 * @return The filelist structure containing the information read from disk.
1095 */
1096struct
1097s_node *process_filelist_and_biggielist()
1098{
1099struct s_node *filelist;
1100
1101/** add mallocs**/
1102char *command;
1103char *tmp;
1104int res = 0;
1105pid_t pid;
1106bool extract_mountlist_stub = FALSE;
1107
1108assert(bkpinfo != NULL);
1109malloc_string(command);
1110malloc_string(tmp);
1111
1112/* If those files already exist, do not overwrite them later on */
1113if (does_file_exist("/"MOUNTLIST_FNAME_STUB)) {
1114    extract_mountlist_stub = FALSE;
1115} else {
1116    extract_mountlist_stub = TRUE;
1117}
1118
1119if (does_file_exist(g_filelist_full)
1120&& does_file_exist(g_biggielist_txt)) {
1121    log_msg(1, "%s exists", g_filelist_full);
1122    log_msg(1, "%s exists", g_biggielist_txt);
1123    log_msg(2,
1124        "Filelist and biggielist already recovered from media. Yay!");
1125} else {
1126    getcwd(tmp, MAX_STR_LEN);
1127    chdir(bkpinfo->tmpdir);
1128    log_msg(1, "chdir(%s)", bkpinfo->tmpdir);
1129    log_to_screen("Extracting filelist and biggielist from media...");
1130    unlink("/tmp/filelist.full");
1131    unlink(FILELIST_FULL_STUB);
1132    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1133        sprintf(command,
1134            "tar -b %ld -zxf %s ./%s ./%s ./%s ./%s ./%s",
1135            bkpinfo->internal_tape_block_size,
1136            bkpinfo->media_device,
1137            MOUNTLIST_FNAME_STUB,
1138            BIGGIELIST_TXT_STUB,
1139            FILELIST_FULL_STUB,
1140            IWANTMYLVM_STUB,
1141            MONDO_CFG_FILE_STUB);
1142        log_msg(1, "tarcommand = %s", command);
1143        run_program_and_log_output(command, 1);
1144        if (!does_file_exist(FILELIST_FULL_STUB)) {
1145            /* Doing that allow us to remain compatible with pre-2.2.5 versions */
1146            log_msg(2, "pre-2.2.4 compatible mode on");
1147            sprintf(command,
1148                "tar -b %ld -zxf %s %s %s %s %s %s",
1149                bkpinfo->internal_tape_block_size,
1150                bkpinfo->media_device,
1151                MOUNTLIST_FNAME_STUB,
1152                BIGGIELIST_TXT_STUB,
1153                FILELIST_FULL_STUB,
1154                IWANTMYLVM_STUB,
1155                MONDO_CFG_FILE_STUB);
1156            log_msg(1, "tarcommand = %s", command);
1157            run_program_and_log_output(command, 1);
1158        }
1159    } else {
1160        log_msg(2,
1161            "Calling insist_on_this_cd_number; bkpinfo->isodir=%s",
1162            bkpinfo->isodir);
1163        insist_on_this_cd_number(1);
1164        log_msg(2, "Back from iotcn");
1165        run_program_and_log_output("mount", 1);
1166        sprintf(command,
1167            "tar -zxf %s/images/all.tar.gz ./%s ./%s ./%s ./%s ./%s",
1168            MNT_CDROM,
1169            MOUNTLIST_FNAME_STUB,
1170            BIGGIELIST_TXT_STUB,
1171            FILELIST_FULL_STUB,
1172            IWANTMYLVM_STUB,
1173            MONDO_CFG_FILE_STUB);
1174
1175        log_msg(1, "tarcommand = %s", command);
1176        run_program_and_log_output(command, 1);
1177        if (!does_file_exist(FILELIST_FULL_STUB)) {
1178            /* Doing that allow us to remain compatible with pre-2.2.5 versions */
1179            log_msg(2, "pre-2.2.4 compatible mode on");
1180            sprintf(command,
1181                "tar -zxf %s/images/all.tar.gz %s %s %s %s %s",
1182                MNT_CDROM,
1183                MOUNTLIST_FNAME_STUB,
1184                BIGGIELIST_TXT_STUB,
1185                FILELIST_FULL_STUB,
1186                IWANTMYLVM_STUB,
1187                MONDO_CFG_FILE_STUB);
1188
1189            log_msg(1, "tarcommand = %s", command);
1190            run_program_and_log_output(command, 1);
1191        }
1192        if (!does_file_exist(BIGGIELIST_TXT_STUB)) {
1193            fatal_error
1194                ("all.tar.gz did not include " BIGGIELIST_TXT_STUB);
1195        }
1196        if (!does_file_exist(FILELIST_FULL_STUB)) {
1197            fatal_error
1198                ("all.tar.gz did not include " FILELIST_FULL_STUB);
1199        }
1200    }
1201    sprintf(command, "cp -f %s %s", MONDO_CFG_FILE_STUB,
1202        g_mondo_cfg_file);
1203    run_program_and_log_output(command, FALSE);
1204
1205    sprintf(command, "cp -f %s/%s %s", bkpinfo->tmpdir,
1206        BIGGIELIST_TXT_STUB, g_biggielist_txt);
1207    log_msg(1, "command = %s", command);
1208    paranoid_system(command);
1209    sprintf(command, "ln -sf %s/%s %s", bkpinfo->tmpdir,
1210        FILELIST_FULL_STUB, g_filelist_full);
1211    log_msg(1, "command = %s", command);
1212    paranoid_system(command);
1213    }
1214
1215    if (am_I_in_disaster_recovery_mode()
1216    &&
1217    /* If it was there, do not overwrite it */
1218    (extract_mountlist_stub) 
1219    &&
1220    ask_me_yes_or_no("Do you want to retrieve the mountlist as well?"))
1221    {
1222        sprintf(command, "ln -sf %s/%s /tmp", MOUNTLIST_FNAME_STUB,
1223            bkpinfo->tmpdir);
1224    paranoid_system(command);
1225    }
1226
1227    chdir(tmp);
1228
1229    if (!does_file_exist(g_biggielist_txt)) {
1230        log_msg(1, "Warning - %s not found", g_biggielist_txt);
1231    }
1232    if (!does_file_exist(g_filelist_full)) {
1233        log_msg(1, "Warning - %s does not exist", g_filelist_full);
1234    }
1235//  popup_and_OK("Wonderful.");
1236
1237    log_msg(2, "Forking");
1238    pid = fork();
1239    switch (pid) {
1240    case -1:
1241        fatal_error("Forking error");
1242        break;
1243
1244    case 0:
1245        log_to_screen("Pre-processing filelist");
1246        if (!does_file_exist(g_biggielist_txt)) {
1247            sprintf(command, "echo -n > %s", g_biggielist_txt);
1248            paranoid_system(command);
1249        }
1250        sprintf(command, "grep -E '^/dev/.*' %s > %s",
1251                g_biggielist_txt, g_filelist_imagedevs);
1252        paranoid_system(command);
1253        exit(0);
1254        break;
1255
1256    default:
1257        open_evalcall_form("Pre-processing filelist");
1258        while (!waitpid(pid, (int *) 0, WNOHANG)) {
1259            usleep(100000);
1260            update_evalcall_form(0);
1261        }
1262    }
1263    close_evalcall_form();
1264
1265    log_msg(3, "loading filelist");
1266    filelist = load_filelist(g_filelist_full);
1267    log_msg(3, "deleting original filelist");
1268    unlink(g_filelist_full);
1269    if (g_text_mode) {
1270        printf("Restore which directory? --> ");
1271        fgets(tmp, sizeof(tmp), stdin);
1272        toggle_path_selection(filelist, tmp, TRUE);
1273        if (strlen(tmp) == 0) {
1274            res = 1;
1275        } else {
1276            res = 0;
1277        }
1278    } else {
1279        res = edit_filelist(filelist);
1280    }
1281    if (res) {
1282        log_msg(2, "User hit 'cancel'. Freeing filelist and aborting.");
1283        free_filelist(filelist);
1284        return (NULL);
1285    }
1286    ask_about_these_imagedevs(g_filelist_imagedevs, g_imagedevs_restthese);
1287    close_evalcall_form();
1288
1289    // NB: It's not necessary to add g_biggielist_txt to the filelist.full
1290    // file. The filelist.full file already contains the filename of EVERY
1291    // file backed up - regular and biggie files.
1292
1293    // However, we do want to make sure the imagedevs selected by the user
1294    // are flagged for restoring.
1295    if (length_of_file(g_imagedevs_restthese) > 2) {
1296        add_list_of_files_to_filelist(filelist, g_imagedevs_restthese,
1297                                      TRUE);
1298    }
1299
1300    paranoid_free(command);
1301    paranoid_free(tmp);
1302    return (filelist);
1303}
1304
1305/**************************************************************************
1306 *END_ PROCESS_FILELIST_AND_BIGGIELIST                                    *
1307 **************************************************************************/
1308
1309
1310
1311
1312/**
1313 * Make a backup copy of <tt>path_root</tt>/<tt>filename</tt>.
1314 * The backup filename is the filename of the original with ".pristine" added.
1315 * @param path_root The place where the filesystem is mounted (e.g. MNT_RESTORING).
1316 * @param filename The filename (absolute path) within @p path_root.
1317 * @return 0 for success, nonzero for failure.
1318 */
1319int backup_crucial_file(char *path_root, char *filename)
1320{
1321    char *tmp;
1322    char *command;
1323    int res;
1324
1325    malloc_string(tmp);
1326    malloc_string(command);
1327    assert(path_root != NULL);
1328    assert_string_is_neither_NULL_nor_zerolength(filename);
1329
1330    sprintf(tmp, "%s/%s", path_root, filename);
1331    sprintf(command, "cp -f %s %s.pristine", tmp, tmp);
1332
1333    res = run_program_and_log_output(command, 5);
1334    paranoid_free(tmp);
1335    paranoid_free(command);
1336    return (res);
1337}
1338
1339void offer_to_make_initrd() {
1340
1341if (bkpinfo->restore_mode != nuke) {
1342    if (ask_me_yes_or_no
1343        ("You will now be able to re-generate your initrd.\nThis is especially useful if you changed of hardware configuration, cloned, made P2V, used multipath...\nDo you need to do it ?")) {
1344        log_msg(1,"Launching shell for manual initrd recreation");
1345        popup_and_OK("You'll now be chrooted under your future / partition.\nGo under /boot and rebuild your initrd with\nmkinitrd -f -v initrd-2.x.y.img 2.x.y e.g.\nThen type exit to finish.");
1346        mvaddstr_and_log_it(g_currentY, 0, "Modifying initrd...");
1347        if (!g_text_mode) {
1348            newtSuspend();
1349        }
1350        (void)system("chroot " MNT_RESTORING);
1351        if (!g_text_mode) {
1352            newtResume();
1353        }
1354        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1355    } else {
1356        return;
1357    }
1358} else {
1359    log_to_screen("Non-interactive mode: no way to give you the keyboard so that you re-generate your initrd. Hope it's OK");
1360    log_msg(1,"Non-interactive mode: no way to give you the keyboard so that you re-generate your initrd. Hope it's OK");
1361}
1362}
1363
1364
1365/**
1366 * Install the user's boot loader in the MBR.
1367 * Currently LILO, ELILO, GRUB, RAW (dd of MBR), and the FreeBSD bootloader are supported.
1368 * @param offer_to_hack_scripts If TRUE, then offer to hack the user's fstab for them.
1369 * @return 0 for success, nonzero for failure.
1370 */
1371int run_boot_loader(bool offer_to_hack_scripts)
1372{
1373    int res;
1374    int retval = 0;
1375
1376  /** malloc *******/
1377    char *device;
1378    char *tmp = NULL;
1379    char *name;
1380    char *cmd = NULL;
1381
1382    malloc_string(device);
1383    malloc_string(name);
1384
1385    /* In order to have a working bootloader, we need to have all devices
1386     * ready in the chroot. If they are not there (udev) then copy them from
1387     * the current /dev location
1388     */
1389    mr_asprintf(&cmd,"tar cf - /dev | ( cd %s ; tar xf - )",MNT_RESTORING);
1390    run_program_and_log_output(cmd, 3);
1391    paranoid_free(cmd);
1392
1393    backup_crucial_file(MNT_RESTORING, "/etc/fstab");
1394    backup_crucial_file(MNT_RESTORING, "/boot/grub/menu.lst");
1395    backup_crucial_file(MNT_RESTORING, "/etc/lilo.conf");
1396    backup_crucial_file(MNT_RESTORING, "/etc/elilo.conf");
1397    backup_crucial_file(MNT_RESTORING, "/boot/grub/device.map");
1398    backup_crucial_file(MNT_RESTORING, "/etc/mtab");
1399    read_cfg_var(g_mondo_cfg_file, "bootloader.device", device);
1400    read_cfg_var(g_mondo_cfg_file, "bootloader.name", name);
1401    mr_asprintf(&tmp, "run_boot_loader: device='%s', name='%s'", device, name);
1402    log_msg(2, tmp);
1403    paranoid_free(tmp);
1404    system("sync");
1405
1406    offer_to_make_initrd();
1407    if (!strcmp(name, "LILO")) {
1408        res = run_lilo(offer_to_hack_scripts);
1409    } else if (!strcmp(name, "ELILO")) {
1410        res = run_elilo(offer_to_hack_scripts);
1411    } else if (!strcmp(name, "GRUB")) {
1412        res = run_grub(offer_to_hack_scripts, device);
1413    } else if (!strcmp(name, "RAW")) {
1414        res = run_raw_mbr(offer_to_hack_scripts, device);
1415    }
1416#ifdef __FreeBSD__
1417    else if (!strcmp(name, "BOOT0")) {
1418        mr_asprintf(&tmp, "boot0cfg -B %s", device);
1419        res = run_program_and_log_output(tmp, FALSE);
1420        paranoid_free(tmp);
1421    } else {
1422        mr_asprintf(&tmp, "ls /dev | grep -Eq '^%ss[1-4].*'", device);
1423        if (!system(tmp)) {
1424            paranoid_free(tmp);
1425            mr_asprintf(&tmp, MNT_RESTORING "/sbin/fdisk -B %s", device);
1426            res = run_program_and_log_output(tmp, 3);
1427        } else {
1428            log_msg(1,
1429                    "I'm not running any boot loader. You have a DD boot drive. It's already loaded up.");
1430        }
1431        paranoid_free(tmp);
1432    }
1433#else
1434    else {
1435        log_to_screen
1436            ("Unable to determine type of boot loader. Defaulting to LILO.");
1437        res = run_lilo(offer_to_hack_scripts);
1438    }
1439#endif
1440    retval += res;
1441    if (res) {
1442        log_to_screen("Your boot loader returned an error");
1443    } else {
1444        log_to_screen("Your boot loader ran OK");
1445    }
1446    paranoid_free(device);
1447    paranoid_free(name);
1448    return (retval);
1449}
1450
1451/**************************************************************************
1452 *END_ RUN_BOOT_LOADER                                                    *
1453 **************************************************************************/
1454
1455
1456
1457/**
1458 * Attempt to find the user's editor.
1459 * @return The editor found ("vi" if none could be found).
1460 * @note The returned string points to static storage that will be overwritten with each call.
1461 */
1462char *find_my_editor(void)
1463{
1464    static char output[MAX_STR_LEN];
1465    if (find_home_of_exe("pico")) {
1466        strcpy(output, "pico");
1467    } else if (find_home_of_exe("nano")) {
1468        strcpy(output, "nano");
1469    } else if (find_home_of_exe("e3em")) {
1470        strcpy(output, "e3em");
1471    } else if (find_home_of_exe("e3vi")) {
1472        strcpy(output, "e3vi");
1473    } else {
1474        strcpy(output, "vi");
1475    }
1476    if (!find_home_of_exe(output)) {
1477        log_msg(2, " (find_my_editor) --- warning - %s not found", output);
1478    }
1479    return (output);
1480}
1481
1482
1483/**
1484 * Install GRUB on @p bd.
1485 * @param offer_to_run_stabgrub If TRUE, then offer to hack the user's fstab for them.
1486 * @param bd The boot device where GRUB is installed.
1487 * @return 0 for success, nonzero for failure.
1488 */
1489int run_grub(bool offer_to_run_stabgrub, char *bd)
1490{
1491  /** malloc **/
1492    char *command;
1493    char *boot_device;
1494    char *rootdev;
1495    char *rootdrive;
1496    char *conffile;
1497    char *tmp;
1498    char *editor;
1499
1500    int res;
1501    int done;
1502
1503    malloc_string(command);
1504    malloc_string(boot_device);
1505    malloc_string(tmp);
1506    malloc_string(editor);
1507    malloc_string(rootdev);
1508    malloc_string(rootdrive);
1509    malloc_string(conffile);
1510    assert_string_is_neither_NULL_nor_zerolength(bd);
1511    strcpy(editor, find_my_editor());
1512    strcpy(boot_device, bd);
1513
1514    if (!run_program_and_log_output("which grub-MR", FALSE)) {
1515        log_msg(1, "Yay! grub-MR found...");
1516        sprintf(command, "grub-MR %s /tmp/mountlist.txt", boot_device);
1517        log_msg(1, "command = %s", command);
1518    } else {
1519        sprintf(command, "chroot " MNT_RESTORING " grub-install %s",
1520                boot_device);
1521        log_msg(1, "WARNING - grub-MR not found; using grub-install");
1522    }
1523    if (offer_to_run_stabgrub
1524        && ask_me_yes_or_no("Did you change the mountlist or cloned the system ?"))
1525        /* interactive mode */
1526    {
1527        mvaddstr_and_log_it(g_currentY,
1528                            0,
1529                            "Modifying fstab, mtab, device.map and menu.lst, and running GRUB...                             ");
1530        for (done = FALSE; !done;) {
1531            popup_and_get_string("Boot device",
1532                                 "Please confirm/enter the boot device. If in doubt, try /dev/hda",
1533                                 boot_device, MAX_STR_LEN / 4);
1534            sprintf(command, "stabgrub-me %s", boot_device);
1535            res = run_program_and_log_output(command, 1);
1536            if (res) {
1537                popup_and_OK
1538                    ("GRUB installation failed. Please install manually using 'grub-install' or similar command. You are now chroot()'ed to your restored system. Please type 'exit' when you are done.");
1539                newtSuspend();
1540                system("chroot " MNT_RESTORING);
1541                newtResume();
1542                popup_and_OK("Thank you.");
1543            } else {
1544                done = TRUE;
1545            }
1546            popup_and_OK("You will now edit fstab, mtab, device.map and menu.lst");
1547            if (!g_text_mode) {
1548                newtSuspend();
1549            }
1550            sprintf(tmp, "chroot %s %s /etc/fstab", MNT_RESTORING, editor);
1551            paranoid_system(tmp);
1552            sprintf(tmp, "chroot %s %s /etc/mtab", MNT_RESTORING, editor);
1553            paranoid_system(tmp);
1554            sprintf(tmp, "chroot %s %s /boot/grub/menu.lst", MNT_RESTORING, editor);
1555            paranoid_system(tmp);
1556            sprintf(tmp, "chroot %s %s /boot/grub/device.map", MNT_RESTORING, editor);
1557            paranoid_system(tmp);
1558            if (!g_text_mode) {
1559                newtResume();
1560            }
1561        }
1562    } else
1563        /* nuke mode */
1564    {
1565        mvaddstr_and_log_it(g_currentY,
1566                            0,
1567                            "Running GRUB...                                                 ");
1568        log_it("%s",command);
1569        res = run_program_and_log_output(command, 1);
1570        if (res) {
1571            popup_and_OK
1572                ("Because of bugs in GRUB's own installer, GRUB was not installed properly. Please install the boot loader manually now, using this chroot()'ed shell prompt. Type 'exit' when you have finished.");
1573            newtSuspend();
1574            system("chroot " MNT_RESTORING);
1575            newtResume();
1576            popup_and_OK("Thank you.");
1577        }
1578    }
1579    if (res) {
1580        mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1581        log_to_screen
1582            ("GRUB ran w/error(s). See %s for more info.", MONDO_LOGFILE);
1583        log_msg(1, "Type:-");
1584        log_msg(1, "    mount-me");
1585        log_msg(1, "    chroot " MNT_RESTORING);
1586        log_msg(1, "    mount /boot");
1587        log_msg(1, "    grub-install '(hd0)'");
1588        log_msg(1, "    exit");
1589        log_msg(1, "    unmount-me");
1590        log_msg(1,
1591                "If you're really stuck, please e-mail the mailing list.");
1592    } else {
1593        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1594    }
1595    paranoid_free(rootdev);
1596    paranoid_free(rootdrive);
1597    paranoid_free(conffile);
1598    paranoid_free(command);
1599    paranoid_free(boot_device);
1600    paranoid_free(tmp);
1601    paranoid_free(editor);
1602
1603    return (res);
1604}
1605
1606/**************************************************************************
1607 *END_RUN_GRUB                                                            *
1608 **************************************************************************/
1609
1610
1611/**
1612 * Install ELILO on the user's boot drive (determined by elilo.conf).
1613 * @param offer_to_run_stabelilo If TRUE, then offer to hack the user's fstab for them.
1614 * @return 0 for success, nonzero for failure.
1615 */
1616int run_elilo(bool offer_to_run_stabelilo)
1617{
1618  /** malloc **/
1619    char *command;
1620    char *tmp;
1621    char *editor;
1622
1623    int res;
1624    int done;
1625
1626    malloc_string(command);
1627    malloc_string(tmp);
1628    malloc_string(editor);
1629    strcpy(editor, find_my_editor());
1630    if (offer_to_run_stabelilo
1631        && ask_me_yes_or_no("Did you change the mountlist or cloned the system ?"))
1632
1633        /* interactive mode */
1634    {
1635        mvaddstr_and_log_it(g_currentY,
1636                            0,
1637                            "Modifying fstab and elilo.conf...                             ");
1638        sprintf(command, "stabelilo-me");
1639        res = run_program_and_log_output(command, 3);
1640        if (res) {
1641            popup_and_OK
1642                ("You will now edit fstab and elilo.conf, to make sure they match your new mountlist.");
1643            for (done = FALSE; !done;) {
1644                if (!g_text_mode) {
1645                    newtSuspend();
1646                }
1647                sprintf(tmp, "chroot %s %s /etc/fstab", MNT_RESTORING, editor);
1648                paranoid_system(tmp);
1649                sprintf(tmp, "chroot %s %s /etc/elilo.conf", MNT_RESTORING, editor);
1650                paranoid_system(tmp);
1651                if (!g_text_mode) {
1652                    newtResume();
1653                }
1654//              newtCls();
1655                if (ask_me_yes_or_no("Edit them again?")) {
1656                    continue;
1657                }
1658                done = TRUE;
1659            }
1660        } else {
1661            log_to_screen("elilo.conf and fstab were modified OK");
1662        }
1663    } else
1664        /* nuke mode */
1665    {
1666        res = TRUE;
1667    }
1668    paranoid_free(command);
1669    paranoid_free(tmp);
1670    paranoid_free(editor);
1671    return (res);
1672}
1673
1674/**************************************************************************
1675 *END_RUN_ELILO                                                            *
1676 **************************************************************************/
1677
1678
1679/**
1680 * Install LILO on the user's boot drive (determined by /etc/lilo.conf).
1681 * @param offer_to_run_stablilo If TRUE, then offer to hack the user's fstab for them.
1682 * @return 0 for success, nonzero for failure.
1683 */
1684int run_lilo(bool offer_to_run_stablilo)
1685{
1686  /** malloc **/
1687    char *command;
1688    char *tmp;
1689    char *editor;
1690
1691    int res;
1692    int done;
1693    bool run_lilo_M = FALSE;
1694    malloc_string(command);
1695    malloc_string(tmp);
1696    malloc_string(editor);
1697
1698    if (!run_program_and_log_output
1699        ("grep \"boot.*=.*/dev/md\" " MNT_RESTORING "/etc/lilo.conf", 1)) {
1700        run_lilo_M = TRUE;
1701    }
1702
1703    strcpy(editor, find_my_editor());
1704    if (offer_to_run_stablilo
1705        && ask_me_yes_or_no("Did you change the mountlist or cloned the system ?"))
1706
1707        /* interactive mode */
1708    {
1709        mvaddstr_and_log_it(g_currentY,
1710                            0,
1711                            "Modifying fstab and lilo.conf, and running LILO...                             ");
1712        sprintf(command, "stablilo-me");
1713        res = run_program_and_log_output(command, 3);
1714        if (res) {
1715            popup_and_OK
1716                ("You will now edit fstab and lilo.conf, to make sure they match your new mountlist.");
1717            for (done = FALSE; !done;) {
1718                if (!g_text_mode) {
1719                    newtSuspend();
1720                }
1721                sprintf(tmp, "%s " MNT_RESTORING "/etc/fstab", editor);
1722                paranoid_system(tmp);
1723                sprintf(tmp, "%s " MNT_RESTORING "/etc/lilo.conf", editor);
1724                paranoid_system(tmp);
1725                if (!g_text_mode) {
1726                    newtResume();
1727                }
1728//              newtCls();
1729                if (ask_me_yes_or_no("Edit them again?")) {
1730                    continue;
1731                }
1732                res =
1733                    run_program_and_log_output("chroot " MNT_RESTORING
1734                                               " lilo -L", 3);
1735                if (res) {
1736                    res =
1737                        run_program_and_log_output("chroot " MNT_RESTORING
1738                                                   " lilo", 3);
1739                }
1740                if (res) {
1741                    done =
1742                        ask_me_yes_or_no
1743                        ("LILO failed. Re-edit system files?");
1744                } else {
1745                    done = TRUE;
1746                }
1747            }
1748        } else {
1749            log_to_screen("lilo.conf and fstab were modified OK");
1750        }
1751    } else
1752        /* nuke mode */
1753    {
1754        mvaddstr_and_log_it(g_currentY,
1755                            0,
1756                            "Running LILO...                                                 ");
1757        res =
1758            run_program_and_log_output("chroot " MNT_RESTORING " lilo -L",
1759                                       3);
1760        if (res) {
1761            res =
1762                run_program_and_log_output("chroot " MNT_RESTORING " lilo",
1763                                           3);
1764        }
1765        if (res) {
1766            mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1767            log_to_screen
1768                ("Failed to re-jig fstab and/or lilo. Edit/run manually, please.");
1769        } else {
1770            mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1771        }
1772    }
1773    if (run_lilo_M) {
1774        run_program_and_log_output("chroot " MNT_RESTORING
1775                                   " lilo -M /dev/hda", 3);
1776        run_program_and_log_output("chroot " MNT_RESTORING
1777                                   " lilo -M /dev/sda", 3);
1778    }
1779    paranoid_free(command);
1780    paranoid_free(tmp);
1781    paranoid_free(editor);
1782    return (res);
1783}
1784
1785/**************************************************************************
1786 *END_RUN_LILO                                                            *
1787 **************************************************************************/
1788
1789
1790/**
1791 * Install a raw MBR onto @p bd.
1792 * @param offer_to_hack_scripts If TRUE, then offer to hack the user's fstab for them.
1793 * @param bd The device to copy the stored MBR to.
1794 * @return 0 for success, nonzero for failure.
1795 */
1796int run_raw_mbr(bool offer_to_hack_scripts, char *bd)
1797{
1798  /** malloc **/
1799    char *command;
1800    char *boot_device;
1801    char *tmp;
1802    char *editor;
1803    int res;
1804    int done;
1805
1806    malloc_string(command);
1807    malloc_string(boot_device);
1808    malloc_string(tmp);
1809    malloc_string(editor);
1810    assert_string_is_neither_NULL_nor_zerolength(bd);
1811
1812    strcpy(editor, find_my_editor());
1813    strcpy(boot_device, bd);
1814    sprintf(command, "raw-MR %s /tmp/mountlist.txt", boot_device);
1815    log_msg(2, "run_raw_mbr() --- command='%s'", command);
1816
1817    if (offer_to_hack_scripts
1818        && ask_me_yes_or_no("Did you change the mountlist or cloned the system ?"))
1819        /* interactive mode */
1820    {
1821        mvaddstr_and_log_it(g_currentY, 0,
1822                            "Modifying fstab and restoring MBR...                           ");
1823        for (done = FALSE; !done;) {
1824            if (!run_program_and_log_output("which vi", FALSE)) {
1825                popup_and_OK("You will now edit fstab");
1826                if (!g_text_mode) {
1827                    newtSuspend();
1828                }
1829                sprintf(tmp, "%s " MNT_RESTORING "/etc/fstab", editor);
1830                paranoid_system(tmp);
1831                if (!g_text_mode) {
1832                    newtResume();
1833                }
1834//              newtCls();
1835            }
1836            popup_and_get_string("Boot device",
1837                                 "Please confirm/enter the boot device. If in doubt, try /dev/hda",
1838                                 boot_device, MAX_STR_LEN / 4);
1839            sprintf(command, "stabraw-me %s", boot_device);
1840            res = run_program_and_log_output(command, 3);
1841            if (res) {
1842                done = ask_me_yes_or_no("Modifications failed. Re-try?");
1843            } else {
1844                done = TRUE;
1845            }
1846        }
1847    } else
1848        /* nuke mode */
1849    {
1850        mvaddstr_and_log_it(g_currentY, 0,
1851                            "Restoring MBR...                                               ");
1852        res = run_program_and_log_output(command, 3);
1853    }
1854    if (res) {
1855        mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1856        log_to_screen
1857            ("MBR+fstab processed w/error(s). See %s for more info.", MONDO_LOGFILE);
1858    } else {
1859        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1860    }
1861    paranoid_free(command);
1862    paranoid_free(boot_device);
1863    paranoid_free(tmp);
1864    paranoid_free(editor);
1865    return (res);
1866}
1867
1868/**************************************************************************
1869 *END_RUN_RAW_MBR                                                         *
1870 **************************************************************************/
1871
1872
1873
1874/**
1875 * malloc() and set sensible defaults for the mondorestore filename variables.
1876 * @param bkpinfo The backup information structure. Fields used:
1877 * - @c bkpinfo->tmpdir
1878 * - @c bkpinfo->disaster_recovery
1879 */
1880void setup_MR_global_filenames()
1881{
1882    char *temppath;
1883
1884    assert(bkpinfo != NULL);
1885
1886    malloc_string(g_biggielist_txt);
1887    malloc_string(g_filelist_full);
1888    malloc_string(g_filelist_imagedevs);
1889    malloc_string(g_imagedevs_restthese);
1890    malloc_string(g_mondo_cfg_file);
1891    malloc_string(g_mountlist_fname);
1892    malloc_string(g_mondo_home);
1893    /*
1894    malloc_string(g_tmpfs_mountpt);
1895    */
1896    malloc_string(g_isodir_device);
1897    malloc_string(g_isodir_format);
1898
1899    temppath = bkpinfo->tmpdir;
1900
1901    sprintf(g_biggielist_txt, "%s/%s", temppath, BIGGIELIST_TXT_STUB);
1902    sprintf(g_filelist_full, "%s/%s", temppath, FILELIST_FULL_STUB);
1903    sprintf(g_filelist_imagedevs, "%s/tmp/filelist.imagedevs", temppath);
1904//  sprintf(g_imagedevs_pot, "%s/tmp/imagedevs.pot", temppath);
1905    sprintf(g_imagedevs_restthese, "%s/tmp/imagedevs.restore-these",
1906            temppath);
1907    if (bkpinfo->disaster_recovery) {
1908        sprintf(g_mondo_cfg_file, "/%s", MONDO_CFG_FILE_STUB);
1909        sprintf(g_mountlist_fname, "/%s", MOUNTLIST_FNAME_STUB);
1910    } else {
1911        sprintf(g_mondo_cfg_file, "%s/%s", temppath, MONDO_CFG_FILE_STUB);
1912        sprintf(g_mountlist_fname, "%s/%s", temppath,
1913                MOUNTLIST_FNAME_STUB);
1914    }
1915}
1916
1917/**************************************************************************
1918 *END_SET_GLOBAL_FILENAME                                                 *
1919 **************************************************************************/
1920
1921
1922/**
1923 * Copy @p input_file (containing the result of a compare) to @p output_file,
1924 * deleting spurious "changes" along the way.
1925 * @param output_file The output file to write with spurious changes removed.
1926 * @param input_file The input file, a list of changed files created by a compare.
1927 */
1928void streamline_changes_file(char *output_file, char *input_file)
1929{
1930    FILE *fin;
1931    FILE *fout;
1932  /** malloc **/
1933    char *incoming;
1934
1935    assert_string_is_neither_NULL_nor_zerolength(output_file);
1936    assert_string_is_neither_NULL_nor_zerolength(input_file);
1937    malloc_string(incoming);
1938
1939    if (!(fin = fopen(input_file, "r"))) {
1940        log_OS_error(input_file);
1941        return;
1942    }
1943    if (!(fout = fopen(output_file, "w"))) {
1944        fatal_error("cannot open output_file");
1945    }
1946    for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
1947         fgets(incoming, MAX_STR_LEN - 1, fin)) {
1948        if (strncmp(incoming, "etc/adjtime", 11)
1949            && strncmp(incoming, "etc/mtab", 8)
1950            && strncmp(incoming, "tmp/", 4)
1951            && strncmp(incoming, "boot/map", 8)
1952            && !strstr(incoming, "incheckentry")
1953            && strncmp(incoming, "etc/mail/statistics", 19)
1954            && strncmp(incoming, "var/", 4))
1955            fprintf(fout, "%s", incoming);  /* don't need \n here, for some reason.. */
1956    }
1957    paranoid_fclose(fout);
1958    paranoid_fclose(fin);
1959    paranoid_free(incoming);
1960}
1961
1962/**************************************************************************
1963 *END_STREAMLINE_CHANGES_FILE                                             *
1964 **************************************************************************/
1965
1966
1967/**
1968 * Give the user twenty seconds to press Ctrl-Alt-Del before we nuke their drives.
1969 */
1970void twenty_seconds_til_yikes()
1971{
1972    int i;
1973    /* MALLOC * */
1974    char *tmp;
1975
1976    malloc_string(tmp);
1977    if (does_file_exist("/tmp/NOPAUSE")) {
1978        return;
1979    }
1980    open_progress_form("CAUTION",
1981                       "Be advised: I am about to ERASE your hard disk(s)!",
1982                       "You may press Ctrl+Alt+Del to abort safely.",
1983                       "", 20);
1984    for (i = 0; i < 20; i++) {
1985        g_current_progress = i;
1986        sprintf(tmp, "You have %d seconds left to abort.", 20 - i);
1987        update_progress_form(tmp);
1988        sleep(1);
1989    }
1990    close_progress_form();
1991    paranoid_free(tmp);
1992}
1993
1994/**************************************************************************
1995 *END_TWENTY_SECONDS_TIL_YIKES                                            *
1996 **************************************************************************/
1997
1998
1999/**
2000 * Unmount all devices in @p p_external_copy_of_mountlist.
2001 * @param p_external_copy_of_mountlist The mountlist to guide the devices to unmount.
2002 * @return 0 for success, nonzero for failure.
2003 */
2004int unmount_all_devices(struct mountlist_itself
2005                        *p_external_copy_of_mountlist)
2006{
2007    struct mountlist_itself *mountlist;
2008    int retval = 0, lino, res = 0, i;
2009    char *command;
2010    char *tmp = NULL;
2011
2012    malloc_string(command);
2013    assert(p_external_copy_of_mountlist != NULL);
2014
2015    mountlist = malloc(sizeof(struct mountlist_itself));
2016    memcpy((void *) mountlist, (void *) p_external_copy_of_mountlist,
2017           sizeof(struct mountlist_itself));
2018    sort_mountlist_by_mountpoint(mountlist, 0);
2019
2020    run_program_and_log_output("df -m", 3);
2021    mvaddstr_and_log_it(g_currentY, 0, "Unmounting devices      ");
2022    open_progress_form("Unmounting devices",
2023                       "Unmounting all devices that were mounted,",
2024                       "in preparation for the post-restoration reboot.",
2025                       "", mountlist->entries);
2026    chdir("/");
2027    for (i = 0;
2028         i < 10
2029         &&
2030         run_program_and_log_output
2031         ("ps | grep buffer | grep -v \"grep buffer\"", TRUE) == 0;
2032         i++) {
2033        sleep(1);
2034        log_msg(2, "Waiting for buffer() to finish");
2035    }
2036
2037    paranoid_system("sync");
2038
2039    mr_asprintf(&tmp, "cp -f %s " MNT_RESTORING "/var/log", MONDO_LOGFILE);
2040    if (run_program_and_log_output(tmp, FALSE)) {
2041        log_msg(1,
2042                "Error. Failed to copy log to PC's /var/log dir. (Mounted read-only?)");
2043    }
2044    paranoid_free(tmp);
2045    if (does_file_exist("/tmp/DUMBASS-GENTOO")) {
2046        run_program_and_log_output("mkdir -p " MNT_RESTORING
2047                                   "/mnt/.boot.d", 5);
2048    }
2049
2050    /* Unmounting the local /proc and /sys first */
2051    run_program_and_log_output("umount " MNT_RESTORING "/proc",3);
2052    run_program_and_log_output("umount " MNT_RESTORING "/sys",3);
2053
2054    for (lino = mountlist->entries - 1; lino >= 0; lino--) {
2055        if (!strcmp(mountlist->el[lino].mountpoint, "lvm")) {
2056            continue;
2057        }
2058        mr_asprintf(&tmp, "Unmounting device %s  ", mountlist->el[lino].device);
2059
2060        update_progress_form(tmp);
2061
2062        if (is_this_device_mounted(mountlist->el[lino].device)) {
2063            if (!strcmp(mountlist->el[lino].mountpoint, "swap")) {
2064                sprintf(command, "swapoff %s", mountlist->el[lino].device);
2065            } else {
2066                if (!strcmp(mountlist->el[lino].mountpoint, "/1")) {
2067                    sprintf(command, "umount %s/", MNT_RESTORING);
2068                    log_msg(3,
2069                            "Well, I know a certain kitty-kitty who'll be sleeping with Mommy tonight...");
2070                } else {
2071                    sprintf(command, "umount " MNT_RESTORING "%s",
2072                            mountlist->el[lino].mountpoint);
2073
2074                    /* To support latest Ubuntu where /var is a separate FS
2075                     * Cf: http://linux.derkeiler.com/Mailing-Lists/Ubuntu/2007-04/msg01319.html
2076                     * we need to create some dirs under the real / before unmounting it */
2077                    if (!strcmp(mountlist->el[lino].mountpoint, "/")) {
2078                        run_program_and_log_output("mkdir -p " MNT_RESTORING "/var/lock", FALSE);
2079                        run_program_and_log_output("mkdir -p " MNT_RESTORING "/var/run", FALSE);
2080                    }
2081                }
2082            }
2083            log_msg(10, "The 'umount' command is '%s'", command);
2084            res = run_program_and_log_output(command, 3);
2085        } else {
2086            mr_strcat(tmp, "...not mounted anyway :-) OK");
2087            res = 0;
2088        }
2089        g_current_progress++;
2090        if (res) {
2091            mr_strcat(tmp, "...Failed");
2092            retval++;
2093            log_to_screen(tmp);
2094        } else {
2095            log_msg(2, tmp);
2096        }
2097        paranoid_free(tmp);
2098    }
2099    close_progress_form();
2100    if (retval) {
2101        mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
2102    } else {
2103        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2104    }
2105    if (retval) {
2106        log_to_screen("Unable to unmount some of your partitions.");
2107    } else {
2108        log_to_screen("All partitions were unmounted OK.");
2109    }
2110    free(mountlist);
2111    paranoid_free(command);
2112    return (retval);
2113}
2114
2115/**************************************************************************
2116 *END_UNMOUNT_ALL_DEVICES                                                 *
2117 **************************************************************************/
2118
2119
2120
2121/**
2122 * Extract mondo-restore.cfg and the mountlist from the tape inserted
2123 * to the ./tmp/ directory.
2124 * @param dev The tape device to read from.
2125 * @return 0 for success, nonzero for failure.
2126 */
2127int extract_cfg_file_and_mountlist_from_tape_dev(char *dev)
2128{
2129    char *command;
2130    int res = 0;
2131
2132    malloc_string(command);
2133
2134    if (bkpinfo->use_obdr) {
2135        skip_obdr();
2136    } else {
2137        // BCO: below 32KB seems to block at least on RHAS 2.1 and MDK 10.0
2138        set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
2139    }
2140
2141    sprintf(command,
2142            "dd if=%s bs=%ld count=%ld 2> /dev/null | tar -zx ./%s ./%s ./%s ./%s ./%s",
2143            dev,
2144            bkpinfo->internal_tape_block_size,
2145            1024L * 1024 * 32 / bkpinfo->internal_tape_block_size,
2146            MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB,
2147            BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);
2148    log_msg(2, "command = '%s'", command);
2149    res = run_program_and_log_output(command, -1);
2150    if (res != 0) {
2151        if (does_file_exist(MONDO_CFG_FILE_STUB)) {
2152            res = 0;
2153        } else {
2154            /* Doing that allow us to remain compatible with pre-2.2.5 versions */
2155            log_msg(2, "pre-2.2.4 compatible mode on");
2156            sprintf(command,
2157                    "dd if=%s bs=%ld count=%ld 2> /dev/null | tar -zx %s %s %s %s %s",
2158                    dev,
2159                    bkpinfo->internal_tape_block_size,
2160                    1024L * 1024 * 32 / bkpinfo->internal_tape_block_size,
2161                    MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB,
2162                    BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);
2163            log_msg(2, "command = '%s'", command);
2164            res = run_program_and_log_output(command, -1);
2165            if ((res != 0) && (does_file_exist(MONDO_CFG_FILE_STUB))) {
2166                res = 0;
2167            }
2168        }
2169    }
2170    paranoid_free(command);
2171    return (res);
2172}
2173
2174
2175
2176/**
2177 * Get the configuration file from the floppy, tape, or CD.
2178 * @param bkpinfo The backup information structure. Fields used:
2179 * - @c bkpinfo->backup_media_type
2180 * - @c bkpinfo->media_device
2181 * - @c bkpinfo->tmpdir
2182 * @return 0 for success, nonzero for failure.
2183 */
2184int get_cfg_file_from_archive()
2185{
2186    int retval = 0;
2187
2188   /** malloc *****/
2189    char *device;
2190    char *command;
2191    char *cfg_file;
2192    char *mounted_cfgf_path;
2193    char *tmp;
2194    char *mountpt;
2195    char *ramdisk_fname;
2196    char *mountlist_file;
2197    bool extract_mountlist_stub = FALSE;
2198    bool extract_i_want_my_lvm = FALSE;
2199
2200    bool try_plan_B;
2201
2202    assert(bkpinfo != NULL);
2203    malloc_string(cfg_file);
2204    malloc_string(mounted_cfgf_path);
2205    malloc_string(mountpt);
2206    malloc_string(ramdisk_fname);
2207    malloc_string(mountlist_file);
2208    malloc_string(device);
2209    malloc_string(command);
2210    malloc_string(tmp);
2211    log_msg(2, "gcffa --- starting");
2212    log_to_screen("I'm thinking...");
2213    sprintf(mountpt, "%s/mount.bootdisk", bkpinfo->tmpdir);
2214    device[0] = '\0';
2215    chdir(bkpinfo->tmpdir);
2216    strcpy(cfg_file, MONDO_CFG_FILE_STUB);
2217    unlink(cfg_file);           // cfg_file[] is missing the '/' at the start, FYI, by intent
2218    unlink(FILELIST_FULL_STUB);
2219    unlink(BIGGIELIST_TXT_STUB);
2220    sprintf(command, "mkdir -p %s", mountpt);
2221    run_program_and_log_output(command, FALSE);
2222
2223    sprintf(cfg_file, "%s/%s", bkpinfo->tmpdir, MONDO_CFG_FILE_STUB);
2224    sprintf(mountlist_file, "%s/%s", bkpinfo->tmpdir, MOUNTLIST_FNAME_STUB);
2225    //   make_hole_for_file( cfg_file );
2226    //   make_hole_for_file( mountlist_file);
2227    log_msg(2, "mountpt = %s; cfg_file=%s", mountpt, cfg_file);
2228
2229    if (!does_file_exist(cfg_file)) {
2230        log_msg(2, "gcffa --- we don't have cfg file yet.");
2231        if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2232            try_plan_B = TRUE;
2233        } else {
2234            log_msg(2, "gcffa --- calling mount_media now :)");
2235            if (!mount_media()) {
2236                log_msg(2,
2237                        "gcffa --- managed to mount CD; so, no need for Plan B");
2238                try_plan_B = FALSE;
2239            } else {
2240                try_plan_B = TRUE;
2241            }
2242            if (what_number_cd_is_this() > 1) {
2243                insist_on_this_cd_number((g_current_media_number = 1));
2244            }
2245        }
2246        if (try_plan_B) {
2247            log_msg(2, "gcffa --- OK, switching to Plan B");
2248            chdir(bkpinfo->tmpdir);
2249            run_program_and_log_output("mkdir -p tmp", FALSE);
2250
2251            if (strlen(bkpinfo->media_device) == 0) {
2252                strcpy(bkpinfo->media_device, "/dev/st0");
2253                log_msg(2, "media_device is blank; assuming %s");
2254            }
2255            strcpy(tmp, bkpinfo->media_device);
2256            if (extract_cfg_file_and_mountlist_from_tape_dev
2257                (bkpinfo->media_device)) {
2258                strcpy(bkpinfo->media_device, "/dev/st0");
2259                if (extract_cfg_file_and_mountlist_from_tape_dev
2260                    (bkpinfo->media_device)) {
2261                    strcpy(bkpinfo->media_device, "/dev/osst0");
2262                    if (extract_cfg_file_and_mountlist_from_tape_dev
2263                        (bkpinfo->media_device)) {
2264                        strcpy(bkpinfo->media_device, "/dev/ht0");
2265                        if (extract_cfg_file_and_mountlist_from_tape_dev
2266                            (bkpinfo->media_device)) {
2267                            log_msg(3,
2268                                    "I tried lots of devices but none worked.");
2269                            strcpy(bkpinfo->media_device, tmp);
2270                        }
2271                    }
2272                }
2273            }
2274
2275            if (!does_file_exist("tmp/mondo-restore.cfg")) {
2276                log_to_screen("Cannot find config info on media");
2277                return (1);
2278            }
2279        } else {
2280                if (does_file_exist("/"MOUNTLIST_FNAME_STUB)) {
2281                    extract_mountlist_stub = FALSE;
2282                } else {
2283                    extract_mountlist_stub = TRUE;
2284                }
2285                if (does_file_exist("/"IWANTMYLVM_STUB)) {
2286                    extract_i_want_my_lvm = FALSE;
2287                } else {
2288                    extract_i_want_my_lvm = TRUE;
2289                }
2290
2291                log_msg(2,
2292                        "gcffa --- Plan B, a.k.a. untarring some file from all.tar.gz");
2293                sprintf(command, "tar -zxvf " MNT_CDROM "/images/all.tar.gz ./%s ./%s ./%s ./%s ./%s", MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB, BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);    // add -b TAPE_BLOCK_SIZE if you _really_ think it's necessary
2294                run_program_and_log_output(command, TRUE);
2295                if (!does_file_exist(MONDO_CFG_FILE_STUB)) {
2296                    /* Doing that allow us to remain compatible with pre-2.2.5 versions */
2297                    log_msg(2, "pre-2.2.4 compatible mode on");
2298                    sprintf(command, "tar -zxvf " MNT_CDROM "/images/all.tar.gz %s %s %s %s %s", MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB, BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);  // add -b TAPE_BLOCK_SIZE if you _really_ think it's necessary
2299                    run_program_and_log_output(command, TRUE);
2300                    if (!does_file_exist(MONDO_CFG_FILE_STUB)) {
2301                        fatal_error
2302                            ("Please reinsert the disk/CD and try again.");
2303                    }
2304                }
2305        }
2306    }
2307    if (does_file_exist(MONDO_CFG_FILE_STUB)) {
2308        log_msg(1, "gcffa --- great! We've got the config file");
2309        sprintf(tmp, "%s/%s",
2310                call_program_and_get_last_line_of_output("pwd"),
2311                MONDO_CFG_FILE_STUB);
2312        sprintf(command, "cp -f %s %s", tmp, cfg_file);
2313        log_it("%s",command);
2314        if (strcmp(tmp, cfg_file)
2315            && run_program_and_log_output(command, 1)) {
2316            log_msg(1,
2317                    "... but an error occurred when I tried to move it to %s",
2318                    cfg_file);
2319        } else {
2320            log_msg(1, "... and I moved it successfully to %s", cfg_file);
2321        }
2322        sprintf(command, "cp -f %s/%s %s",
2323            call_program_and_get_last_line_of_output("pwd"),
2324            MOUNTLIST_FNAME_STUB, mountlist_file);
2325        log_it("%s",command);
2326        if (extract_mountlist_stub) {
2327            if (strcmp(tmp, cfg_file)
2328                && run_program_and_log_output(command, 1)) {
2329                log_msg(1, "Failed to get mountlist");
2330            } else {
2331                log_msg(1, "Got mountlist too");
2332                sprintf(command, "cp -f %s %s", mountlist_file,
2333                        g_mountlist_fname);
2334                if (run_program_and_log_output(command, 1)) {
2335                    log_msg(1, "Failed to copy mountlist to /tmp");
2336                } else {
2337                    log_msg(1, "Copied mountlist to /tmp as well OK");
2338                    sprintf(command, "cp -f %s /tmp/",IWANTMYLVM_STUB);
2339                    run_program_and_log_output(command, 1);
2340                }
2341            }
2342        }
2343    }
2344    run_program_and_log_output("umount " MNT_CDROM, FALSE);
2345    if (!does_file_exist(cfg_file)) {
2346        log_it("%s",cfg_file);
2347        log_msg(1, "%s not found", cfg_file);
2348        log_to_screen
2349            ("Oh dear. Unable to recover configuration file from boot disk");
2350        return (1);
2351    }
2352
2353    log_to_screen("Recovered mondo-restore.cfg");
2354    if (!does_file_exist(MOUNTLIST_FNAME_STUB)) {
2355        log_to_screen("...but not mountlist.txt - a pity, really...");
2356    }
2357    else {
2358            /* Is this code really useful ??? */
2359        if (extract_mountlist_stub) {
2360            sprintf(command, "cp -f %s %s/%s", MOUNTLIST_FNAME_STUB,
2361                    bkpinfo->tmpdir, MOUNTLIST_FNAME_STUB);
2362            run_program_and_log_output(command, FALSE);
2363        }
2364    }
2365
2366    sprintf(command, "cp -f %s /%s", cfg_file, MONDO_CFG_FILE_STUB);
2367    run_program_and_log_output(command, FALSE);
2368    if (extract_mountlist_stub) {
2369        sprintf(command, "cp -f %s /%s", mountlist_file, MOUNTLIST_FNAME_STUB);
2370        run_program_and_log_output(command, FALSE);
2371    }
2372    sprintf(command, "cp -f etc/raidtab /etc/");
2373    run_program_and_log_output(command, FALSE);
2374    if (extract_i_want_my_lvm) {
2375        sprintf(command, "cp -f %s /tmp/",IWANTMYLVM_STUB);
2376        run_program_and_log_output(command, FALSE);
2377    }
2378    g_backup_media_type = bkpinfo->backup_media_type;
2379    paranoid_free(device);
2380    paranoid_free(command);
2381    paranoid_free(tmp);
2382    paranoid_free(cfg_file);
2383    paranoid_free(mounted_cfgf_path);
2384    paranoid_free(mountpt);
2385    paranoid_free(ramdisk_fname);
2386    paranoid_free(mountlist_file);
2387    return (retval);
2388}
2389
2390/**************************************************************************
2391 *END_GET_CFG_FILE_FROM_ARCHIVE                                           *
2392 **************************************************************************/
2393
2394/* @} - end restoreUtilityGroup */
2395
2396
2397/***************************************************************************
2398 * F@                                                                      *
2399 * () -- Hugo Rabson                                  *
2400 *                                                                         *
2401 * Purpose:                                                                *
2402 *                                                                         *
2403 * Called by:                                                              *
2404 * Params:    -                      -                                     *
2405 * Returns:   0=success; nonzero=failure                                   *
2406 ***************************************************************************/
2407
2408
2409
2410void wait_until_software_raids_are_prepped(char *mdstat_file,
2411                                           int wait_for_percentage)
2412{
2413    struct raidlist_itself *raidlist;
2414    int unfinished_mdstat_devices = 9999, i;
2415    char *screen_message;
2416
2417    malloc_string(screen_message);
2418    raidlist = malloc(sizeof(struct raidlist_itself));
2419
2420    assert(wait_for_percentage <= 100);
2421    log_it("wait_until_software_raids_are_prepped");
2422    while (unfinished_mdstat_devices > 0) {
2423            // FIXME: Prefix '/dev/' should really be dynamic!
2424        if (parse_mdstat(raidlist, "/dev/")) {
2425            log_to_screen("Sorry, cannot read %s", MDSTAT_FILE);
2426            log_msg(1,"Sorry, cannot read %s", MDSTAT_FILE);
2427            return;
2428        }
2429        for (unfinished_mdstat_devices = i = 0; i <= raidlist->entries; i++) {
2430            if (raidlist->el[i].progress < wait_for_percentage) {
2431                unfinished_mdstat_devices++;
2432                if (raidlist->el[i].progress == -1) // delayed while another partition inits
2433                {
2434                    continue;
2435                }
2436                log_msg(1,"Sync'ing %s (i=%d)", raidlist->el[i].raid_device, i);
2437                sprintf(screen_message, "Sync'ing %s",
2438                        raidlist->el[i].raid_device);
2439                open_evalcall_form(screen_message);
2440                while (raidlist->el[i].progress < wait_for_percentage) {
2441                    log_msg(1,"Percentage sync'ed: %d", raidlist->el[i].progress);
2442                    update_evalcall_form(raidlist->el[i].progress);
2443                    sleep(2);
2444                    // FIXME: Prefix '/dev/' should really be dynamic!
2445                    if (parse_mdstat(raidlist, "/dev/")) {
2446                        break;
2447                    }
2448                }
2449                close_evalcall_form();
2450            }
2451        }
2452    }
2453    paranoid_free(screen_message);
2454    paranoid_free(raidlist);
2455}
2456
2457
Note: See TracBrowser for help on using the repository browser.