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

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