source: branches/stable/mondo/src/mondorestore/mondorestore.c

Last change on this file was 1977, checked in by bruno, 11 years ago

svn merge -r 1938:1976 $SVN_M/branches/2.2.6

  • Property svn:keywords set to Id
File size: 198.4 KB
Line 
1/***************************************************************************
2* restores mondoarchive data
3* $Id: mondorestore.c 1977 2008-06-02 08:49:01Z bruno $
4***************************************************************************/
5
6/**
7 * @file
8 * The main file for mondorestore.
9 */
10
11/**************************************************************************
12 * #include statements                                                    *
13 **************************************************************************/
14#include <unistd.h>
15#include <utime.h>
16#include <locale.h>
17
18#include "mr_gettext.h"
19#include "my-stuff.h"
20#include "mr_mem.h"
21#include "mr_msg.h"
22#include "mr_str.h"
23#include "mr_err.h"
24#include "mr_conf.h"
25
26#include "mondostructures.h"
27#include "libmondo.h"
28#include "mr-externs.h"
29#include "mondo-restore.h"
30#include "mondorestore.h"
31#include "mondo-rstr-compare-EXT.h"
32#include "mondo-rstr-tools-EXT.h"
33
34#define DEFAULT_MR_LOGLEVEL 4
35
36extern void twenty_seconds_til_yikes(void);
37
38/* Reference to global bkpinfo */
39struct s_bkpinfo *bkpinfo;
40
41/* For use in other programs (ex. XMondo) */
42#ifdef MONDORESTORE_MODULE
43#define main __mondorestore_main
44#define g_ISO_restore_mode __mondorestore_g_ISO_restore_mode
45#endif
46
47//static char cvsid[] = "$Id: mondorestore.c 1977 2008-06-02 08:49:01Z bruno $";
48
49/**************************************************************************
50 * Globals                                                                *
51 **************************************************************************/
52extern char *g_tmpfs_mountpt;   // declared in libmondo-tools.c
53extern bool g_text_mode;
54extern FILE *g_fprep;
55extern double g_kernel_version;
56extern int g_partition_table_locked_up;
57extern int g_noof_rows;
58
59extern int partition_everything(struct mountlist_itself *mountlist);
60
61
62/**
63 * @name Restore-Time Globals
64 * @ingroup globalGroup
65 * @{
66 */
67/**
68 * If TRUE, then SIGPIPE was just caught.
69 * Set by the signal handler; cleared after it's handled.
70 */
71bool g_sigpipe_caught = FALSE;
72
73/**
74 * If TRUE, then we're restoring from ISOs or an NFS server.
75 * If FALSE, then we're restoring from some kind of real media (tape, CD, etc.)
76 */
77bool g_ISO_restore_mode = FALSE;    /* are we in Iso Mode? */
78
79/**
80 * If TRUE, then we have had a successful "nuke" restore.
81 */
82bool g_I_have_just_nuked = FALSE;
83
84/**
85 * The device to mount to get at the ISO images. Ignored unless @p g_ISO_restore_mode.
86 */
87char *g_isodir_device = NULL;
88
89/**
90 * The format of @p g_isodir_device. Ignored unless @p g_ISO_restore_mode.
91 */
92char *g_isodir_format = NULL;
93
94/**
95 * The location of 'biggielist.txt', containing the biggiefiles on the current archive set.
96 */
97char *g_biggielist_txt = NULL;
98
99/**
100 * The location of 'filelist.full', containing all files (<em>including biggiefiles</em>) on
101 * the current archive set.
102 */
103char *g_filelist_full = NULL;
104
105/**
106 * The location of a file containing a list of the devices that were archived
107 * as images, not as individual files.
108 */
109char *g_filelist_imagedevs = NULL;
110
111/**
112 * The location of a file containing a list of imagedevs to actually restore.
113 * @see g_filelist_imagedevs
114 */
115char *g_imagedevs_restthese = NULL;
116
117/**
118 * The location of 'mondo-restore.cfg', containing the metadata
119 * information for this backup.
120 */
121char *g_mondo_cfg_file = NULL;
122
123/**
124 * The location of 'mountlist.txt', containing the information on the
125 * user's partitions and hard drives.
126 */
127char *g_mountlist_fname = NULL;
128
129extern char *g_getfacl;
130extern char *g_getfattr;
131
132/* @} - end of "Restore-Time Globals" in globalGroup */
133
134extern int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived,
135                                 char direction);
136
137struct mr_rs_conf *mr_conf = NULL;
138
139/* destroy the mr_rs_conf structure's content */
140static void mr_rs_clean_conf(struct mr_rs_conf *mr_cnf) {
141   
142    if (mr_cnf == NULL) {
143        return;
144    }
145    mr_free(mr_cnf->media_device);
146    mr_free(mr_cnf->prefix);
147    mr_free(mr_cnf->boot_loader);
148    mr_free(mr_cnf->compression_tool);
149    mr_free(mr_cnf->ui_mode);
150    mr_free(mr_cnf->images_dir);
151}
152
153/* Create the pointer to the function called in mr_exit */
154void (*mr_cleanup)(void) = NULL;
155
156/* Cleanup all memory allocated in various structures */
157void mr_rs_cleanup(void) {
158    /* Highly incomplete function for the moment */
159    /* We have to free all allocated memory */
160        /* Not allocated yet
161    mr_rs_clean_conf(&mr_conf);
162    */
163    mr_rs_clean_conf(NULL);
164    /* We have to remove all temporary files */
165    /* We have to unmount what has been mounted */
166    /* We have to properly end newt */
167    /* We have to remind people of log files */
168
169    mr_msg_close();
170}
171
172/* reset/empty the mr_ar_conf structure from mondo's conf file */
173static void mr_rs_reset_conf(struct mr_rs_conf *mr_cnf) {
174
175    /* This should correspond to the default conf file */
176    /* Especially for boolean values */
177    mr_cnf->media_size = 0;
178    mr_cnf->media_device = NULL;
179    mr_cnf->manual_tray = FALSE;
180    mr_cnf->log_level = 0;
181    mr_cnf->prefix = NULL;
182    mr_cnf->external_tape_blocksize = 0;
183    mr_cnf->internal_tape_blocksize = 0;
184    mr_cnf->boot_loader = NULL;
185    mr_cnf->differential = FALSE;
186    mr_cnf->compression_tool = NULL;
187    mr_cnf->ui_mode = NULL;
188    mr_cnf->automatic_restore = FALSE;
189    mr_cnf->images_dir = NULL;
190}
191
192/**************************************************************************
193 * COMPAQ PROLIANT Stuff:  needs some special help                        *
194**************************************************************************/
195
196/**
197 * The message to display if we detect that the user is using a Compaq Proliant.
198 */
199#define COMPAQ_PROLIANTS_SUCK _("Partition and format your disk using Compaq's disaster recovery CD. After you've done that, please reboot with your Mondo media in Interactive Mode.")
200
201
202/**
203 * Allow the user to modify the mountlist before we partition & format their drives.
204 * @param bkpinfo The backup information structure. @c disaster_recovery is the only field used.
205 * @param mountlist The mountlist to let the user modify.
206 * @param raidlist The raidlist that goes with @p mountlist.
207 * @return 0 for success, nonzero for failure.
208 * @ingroup restoreGuiGroup
209 */
210int let_user_edit_the_mountlist(struct mountlist_itself *mountlist,
211                                struct raidlist_itself *raidlist)
212{
213    int retval = 0, res = 0;
214
215    mr_msg(2, "let_user_edit_the_mountlist() --- starting");
216
217    assert(bkpinfo != NULL);
218    assert(mountlist != NULL);
219    assert(raidlist != NULL);
220    if (!bkpinfo->disaster_recovery) {
221        strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
222        mr_msg(2, "I guess you're testing edit_mountlist()");
223    }
224    if (!does_file_exist(g_mountlist_fname)) {
225        log_to_screen(g_mountlist_fname);
226        log_to_screen(_("does not exist"));
227        return (1);
228    }
229
230    retval = load_mountlist(mountlist, g_mountlist_fname);
231    load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
232    if (retval) {
233        log_to_screen
234            (_("Warning - load_raidtab_into_raidlist returned an error"));
235    }
236    res = edit_mountlist(g_mountlist_fname, mountlist, raidlist);
237    if (res) {
238        return (1);
239    }
240
241    save_mountlist_to_disk(mountlist, g_mountlist_fname);
242    save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME);
243
244    log_to_screen(_("I have finished editing the mountlist for you."));
245
246    return (retval);
247}
248
249
250/**
251 * Determine whether @p mountlist contains a Compaq diagnostic partition.
252 * @param mountlist The mountlist to examine.
253 * @return TRUE if there's a Compaq diagnostic partition; FALSE if not.
254 * @ingroup restoreUtilityGroup
255 */
256bool
257partition_table_contains_Compaq_diagnostic_partition(struct
258                                                     mountlist_itself *
259                                                     mountlist)
260{
261    int i;
262
263    assert(mountlist != NULL);
264
265    for (i = 0; i < mountlist->entries; i++) {
266        if (strstr(mountlist->el[i].format, "ompaq")) {
267            mr_msg(2, "mountlist[%d] (%s) is %s (Compaq alert!)",
268                    i, mountlist->el[i].device, mountlist->el[i].format);
269
270            return (TRUE);
271        }
272    }
273    return (FALSE);
274}
275
276/**************************************************************************
277 *END_PARTITION_TABLE_CONTAINS_COMPAQ_DIAGNOSTIC_PARTITION                *
278 **************************************************************************/
279
280
281/**
282 * Allow the user to abort the backup if we find that there is a Compaq diagnostic partition.
283 * @note This function does not actually check for the presence of a Compaq partition.
284 * @ingroup restoreUtilityGroup
285 */
286void offer_to_abort_because_Compaq_Proliants_suck(void)
287{
288    popup_and_OK(COMPAQ_PROLIANTS_SUCK);
289    if (ask_me_yes_or_no
290        (_("Would you like to reboot and use your Compaq CD to prep your hard drive?")))
291    {
292        fatal_error(_("Aborting. Please reboot and prep your hard drive with your Compaq CD."));
293    }
294}
295
296/**************************************************************************
297 *END_OFFER_TO_ABORT_BECAUSE_COMPAQ_PROLIANTS_SUCK                        *
298 **************************************************************************/
299
300
301/**
302 * Call interactive_mode(), nuke_mode(), or compare_mode() depending on the user's choice.
303 * @param bkpinfo The backup information structure. Most fields are used.
304 * @param mountlist The mountlist containing information about the user's partitions.
305 * @param raidlist The raidlist to go with @p mountlist.
306 * @return The return code from the mode function called.
307 * @ingroup restoreGroup
308 */
309int
310catchall_mode(struct mountlist_itself *mountlist,
311              struct raidlist_itself *raidlist)
312{
313    char c, *tmp;
314    int retval = 0;
315
316    iamhere("inside catchall");
317    assert(bkpinfo != NULL);
318    assert(mountlist != NULL);
319    assert(raidlist != NULL);
320    iamhere("pre wrm");
321    c = which_restore_mode();
322    iamhere("post wrm");
323    if (c == 'I' || c == 'N' || c == 'C') {
324        interactively_obtain_media_parameters_from_user(FALSE);
325    } else {
326        popup_and_OK(_("No restoring or comparing will take place today."));
327        if (is_this_device_mounted("/mnt/cdrom")) {
328            run_program_and_log_output("umount /mnt/cdrom", FALSE);
329        }
330        if (g_ISO_restore_mode) {
331            mr_asprintf(&tmp, "umount %s", bkpinfo->isodir);
332            run_program_and_log_output(tmp, FALSE);
333            mr_free(tmp);
334        }
335        paranoid_MR_finish(0);
336    }
337
338    iamhere("post int");
339
340    if (bkpinfo->backup_media_type == iso) {
341        if (iso_fiddly_bits((c == 'N') ? TRUE : FALSE)) {
342            mr_msg(2,
343                    "catchall_mode --- iso_fiddly_bits returned w/ error");
344            return (1);
345        } else {
346            mr_msg(2, "catchall_mode --- iso_fiddly_bits ok");
347        }
348    }
349
350    if (c == 'I') {
351        mr_msg(2, "IM selected");
352        retval += interactive_mode(mountlist, raidlist);
353    } else if (c == 'N') {
354        mr_msg(2, "NM selected");
355        retval += nuke_mode(mountlist, raidlist);
356    } else if (c == 'C') {
357        mr_msg(2, "CM selected");
358        retval += compare_mode(mountlist, raidlist);
359    }
360    return (retval);
361}
362
363/**************************************************************************
364 *END_CATCHALL_MODE                                                      *
365 **************************************************************************/
366
367/**************************************************************************
368 *END_  EXTRACT_CONFIG_FILE_FROM_RAMDISK                                  *
369 **************************************************************************/
370
371static void clean_blkid() {
372
373    char *tmp1 = NULL;
374
375    /* Clean up blkid cache file if they exist */
376    mr_asprintf(&tmp1,"%s/etc/blkid.tab",bkpinfo->restore_path);
377    (void)unlink(tmp1);
378    mr_free(tmp1);
379    mr_asprintf(&tmp1,"%s/etc/blkid.tab.old",bkpinfo->restore_path);
380    (void)unlink(tmp1);
381    mr_free(tmp1);
382}
383
384
385/**
386 * @addtogroup restoreGroup
387 * @{
388 */
389/**
390 * Restore the user's data, in a disaster recovery situation, prompting the
391 * user about whether or not to do every step.
392 * The user can edit the mountlist, choose files to restore, etc.
393 * @param bkpinfo The backup information structure. Most fields are used.
394 * @param mountlist The mountlist containing information about the user's partitions.
395 * @param raidlist The raidlist to go with @p mountlist.
396 * @return 0 for success, or the number of errors encountered.
397 */
398int
399interactive_mode(struct mountlist_itself *mountlist,
400                 struct raidlist_itself *raidlist)
401{
402    int retval = 0;
403    int res;
404    int ptn_errs = 0;
405    int fmt_errs = 0;
406
407    bool done;
408    bool restore_all;
409
410    char *tmp = NULL;
411    char *tmp1 = NULL;
412    char *fstab_fname = NULL;
413    char *old_restpath = NULL;
414
415    struct s_node *filelist = NULL;
416
417    /* try to partition and format */
418
419    mr_msg(2, "interactive_mode --- starting (great, assertions OK)");
420
421    assert(bkpinfo != NULL);
422    assert(mountlist != NULL);
423    assert(raidlist != NULL);
424
425    mr_msg(2, "interactive_mode --- assertions OK");
426
427    if (g_text_mode) {
428        if (!ask_me_yes_or_no
429            (_("Interactive Mode + textonly = experimental! Proceed anyway?")))
430        {
431            fatal_error("Wise move.");
432        }
433    }
434
435    iamhere("About to load config file");
436    get_cfg_file_from_archive_or_bust();
437    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
438    iamhere("Done loading config file; resizing ML");
439    if (bkpinfo->backup_media_type == nfs) {
440        mr_asprintf(&tmp,bkpinfo->prefix);
441        if (popup_and_get_string
442            ("Prefix", "Prefix of your ISO images ?", tmp, MAX_STR_LEN / 4)) {
443            mr_free(bkpinfo->prefix);
444            bkpinfo->prefix = tmp;
445            mr_msg(1, "Prefix set to %s",bkpinfo->prefix);
446        }
447    }
448   
449#ifdef __FreeBSD__
450    if (strstr
451        (call_program_and_get_last_line_of_output("cat /tmp/cmdline"),
452         "noresize"))
453#else
454    if (strstr
455        (call_program_and_get_last_line_of_output("cat /proc/cmdline"),
456         "noresize"))
457#endif
458    {
459        mr_msg(1, "Not resizing mountlist.");
460    } else {
461        resize_mountlist_proportionately_to_suit_new_drives(mountlist);
462    }
463    for (done = FALSE; !done;) {
464        iamhere("About to edit mountlist");
465        if (g_text_mode) {
466            save_mountlist_to_disk(mountlist, g_mountlist_fname);
467            mr_asprintf(&tmp, "%s %s", find_my_editor(), g_mountlist_fname);
468            res = system(tmp);
469            mr_free(tmp);
470            load_mountlist(mountlist, g_mountlist_fname);
471        } else {
472            res = edit_mountlist(g_mountlist_fname, mountlist, raidlist);
473        }
474        iamhere("Finished editing mountlist");
475        if (res) {
476            paranoid_MR_finish(1);
477        }
478        mr_msg(2, "Proceeding...");
479        save_mountlist_to_disk(mountlist, g_mountlist_fname);
480        save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME);
481        mvaddstr_and_log_it(1, 30, _("Restoring Interactively"));
482        if (bkpinfo->differential) {
483            log_to_screen(_("Because this is a differential backup, disk"));
484            log_to_screen(_(" partitioning and formatting will not take place."));
485            done = TRUE;
486        } else {
487            if (ask_me_yes_or_no
488                (_("Do you want to erase and partition your hard drives?")))
489            {
490                if (partition_table_contains_Compaq_diagnostic_partition
491                    (mountlist)) {
492                    offer_to_abort_because_Compaq_Proliants_suck();
493                    done = TRUE;
494                } else {
495                    twenty_seconds_til_yikes();
496                    g_fprep = fopen("/tmp/prep.sh", "w");
497                    ptn_errs = partition_everything(mountlist);
498                    if (ptn_errs) {
499                        log_to_screen
500                            (_("Warning. Errors occurred during disk partitioning."));
501                    }
502
503                    fmt_errs = format_everything(mountlist, FALSE, raidlist);
504                    if (!fmt_errs) {
505                        log_to_screen
506                            (_("Errors during disk partitioning were handled OK."));
507                        log_to_screen(_("Partitions were formatted OK despite those errors."));
508                        ptn_errs = 0;
509                    }
510                    if (!ptn_errs && !fmt_errs) {
511                        done = TRUE;
512                    }
513                }
514                paranoid_fclose(g_fprep);
515            } else {
516                mvaddstr_and_log_it(g_currentY++, 0,
517                                    _("User opted not to partition the devices"));
518                if (ask_me_yes_or_no
519                    (_("Do you want to format your hard drives?"))) {
520                    fmt_errs =
521                        format_everything(mountlist, TRUE, raidlist);
522                    if (!fmt_errs) {
523                        done = TRUE;
524                    }
525                } else {
526                    ptn_errs = fmt_errs = 0;
527                    done = TRUE;
528                }
529            }
530            if (fmt_errs) {
531                mvaddstr_and_log_it(g_currentY++,
532                                    0,
533                                    _("Errors occurred. Please repartition and format drives manually."));
534                done = FALSE;
535            }
536            if (ptn_errs & !fmt_errs) {
537                mvaddstr_and_log_it(g_currentY++,
538                                    0,
539                                    _("Errors occurred during partitioning. Formatting, however, went OK."));
540                done = TRUE;
541            }
542            if (!done) {
543                if (!ask_me_yes_or_no(_("Re-edit the mountlist?"))) {
544                    retval++;
545                    iamhere("Leaving interactive_mode()");
546                    return (retval);
547                }
548            }
549        }
550    }
551
552    /* mount */
553    if (mount_all_devices(mountlist, TRUE)) {
554        unmount_all_devices(mountlist);
555        retval++;
556        iamhere("Leaving interactive_mode()");
557        return (retval);
558    }
559    /* restore */
560    if ((restore_all =
561         ask_me_yes_or_no(_("Do you want me to restore all of your data?"))))
562    {
563        mr_msg(1, "Restoring all data");
564        retval += restore_everything(NULL);
565    } else if ((restore_all =
566             ask_me_yes_or_no
567             (_("Do you want me to restore _some_ of your data?")))) {
568        mr_asprintf(&old_restpath,bkpinfo->restore_path);
569        for (done = FALSE; !done;) {
570            unlink("/tmp/filelist.full");
571            filelist = process_filelist_and_biggielist();
572            /* Now you have /tmp/tmpfs/filelist.restore-these and /tmp/tmpfs/biggielist.restore-these;
573               the former is a list of regular files; the latter, biggiefiles and imagedevs.
574             */
575            if (filelist) {
576                malloc_string(tmp1);
577              gotos_suck:
578                strcpy(tmp1, old_restpath);
579                // (NB: MNT_RESTORING is where your filesystem is mounted now, by default)
580                if (popup_and_get_string
581                    (_("Restore path"), _("Restore files to where?"), tmp1,
582                     MAX_STR_LEN / 4)) {
583                    if (!strcmp(tmp1, "/")) {
584                        if (!ask_me_yes_or_no(_("Are you sure?"))) {
585                            goto gotos_suck;
586                        }
587                        tmp1[0] = '\0'; // so we restore to [blank]/file/name :)
588                    }
589                    strcpy(bkpinfo->restore_path, tmp1);
590                    mr_msg(1, "Restoring subset");
591                    retval += restore_everything(filelist);
592                    free_filelist(filelist);
593                } else {
594                    strcpy(bkpinfo->restore_path, old_restpath);
595                    free_filelist(filelist);
596                }
597                if (!ask_me_yes_or_no
598                    (_("Restore another subset of your backup?"))) {
599                    done = TRUE;
600                }
601                mr_free(tmp1);
602            } else {
603                done = TRUE;
604            }
605        }
606        mr_free(old_restpath);
607    } else {
608        mvaddstr_and_log_it(g_currentY++,
609                            0,
610                            _("User opted not to restore any data.                                  "));
611    }
612    if (retval) {
613        mvaddstr_and_log_it(g_currentY++,
614                            0,
615                            _("Errors occurred during the restore phase.            "));
616    }
617
618    if (ask_me_yes_or_no(_("Initialize the boot loader?"))) {
619        run_boot_loader(TRUE);
620    } else {
621        mvaddstr_and_log_it(g_currentY++,
622                            0,
623                            _("User opted not to initialize the boot loader."));
624    }
625
626    clean_blkid();
627    protect_against_braindead_sysadmins();
628    retval += unmount_all_devices(mountlist);
629    /*  if (restore_some || restore_all || */
630    if (ask_me_yes_or_no
631        (_("Label/Identify your ext2 and ext3 partitions if necessary?"))) {
632        mvaddstr_and_log_it(g_currentY, 0,
633                            _("Using tune2fs to identify your ext2,3 partitions"));
634        if (does_file_exist("/tmp/fstab.new")) {
635            mr_asprintf(&fstab_fname, "/tmp/fstab.new");
636        } else {
637            mr_asprintf(&fstab_fname, "/tmp/fstab");
638        }
639        mr_asprintf(&tmp,
640                "label-partitions-as-necessary %s < %s >> %s 2>> %s",
641                g_mountlist_fname, fstab_fname, MONDO_LOGFILE,
642                MONDO_LOGFILE);
643        mr_free(fstab_fname);
644
645        res = system(tmp);
646        mr_free(tmp);
647        if (res) {
648            log_to_screen
649                (_("label-partitions-as-necessary returned an error"));
650            mvaddstr_and_log_it(g_currentY++, 74, _("Failed."));
651        } else {
652            mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
653        }
654        retval += res;
655    }
656
657    iamhere("About to leave interactive_mode()");
658    if (retval) {
659        mvaddstr_and_log_it(g_currentY++,
660                            0,
661                            _("Warning - errors occurred during the restore phase."));
662    }
663    iamhere("Leaving interactive_mode()");
664    return(retval);
665}
666
667/**************************************************************************
668 *END_INTERACTIVE_MODE                                                    *
669 **************************************************************************/
670
671
672/**
673 * Run an arbitrary restore mode (prompt the user), but from ISO images
674 * instead of real media.
675 * @param mountlist The mountlist containing information about the user's partitions.
676 * @param raidlist The raidlist that goes with @p mountlist.
677 * @param nuke_me_please If TRUE, we plan to run Nuke Mode.
678 * @return 0 for success, or the number of errors encountered.
679 */
680int
681iso_mode(struct mountlist_itself *mountlist,
682         struct raidlist_itself *raidlist, bool nuke_me_please)
683{
684    char c = ' ';
685    int retval = 0;
686
687    assert(mountlist != NULL);
688    assert(raidlist != NULL);
689    if (iso_fiddly_bits(nuke_me_please)) {
690        mr_msg(1, "iso_mode --- returning w/ error");
691        return (1);
692    } else {
693        c = which_restore_mode();
694        if (c == 'I' || c == 'N' || c == 'C') {
695            interactively_obtain_media_parameters_from_user(FALSE);
696        }
697        if (c == 'I') {
698            retval += interactive_mode(mountlist, raidlist);
699        } else if (c == 'N') {
700            retval += nuke_mode(mountlist, raidlist);
701        } else if (c == 'C') {
702            retval += compare_mode(mountlist, raidlist);
703        } else {
704            log_to_screen(_("OK, I shan't restore/compare any files."));
705        }
706    }
707    if (is_this_device_mounted(MNT_CDROM)) {
708        paranoid_system("umount " MNT_CDROM);
709    }
710    if (system("umount /tmp/isodir 2> /dev/null")) {
711        log_to_screen
712            (_("WARNING - unable to unmount device where the ISO files are stored."));
713    }
714    return (retval);
715}
716
717/**************************************************************************
718 *END_ISO_MODE                                                            *
719 **************************************************************************/
720static void call_me_after_the_nuke(int retval) {
721
722    char *tmp = NULL;
723    char *tmp1 = NULL;
724
725    if (retval) {
726        log_to_screen(_("Errors occurred during the nuke phase."));
727        log_to_screen(_("Please visit our website at http://www.mondorescue.org for more information."));
728    } else {
729#ifdef __FreeBSD__
730    tmp1 = call_program_and_get_last_line_of_output("cat /tmp/cmdline");
731#else
732    tmp1 = call_program_and_get_last_line_of_output("cat /proc/cmdline");
733#endif
734        if (strstr(tmp1,"RESTORE") == NULL) {
735            /* -H option */
736            mr_asprintf(&tmp,
737                _(" Mondo has restored your system. Please remove the backup media and reboot.\n\nPlease visit our website at http://www.mondorescue.org for more information."));
738            popup_and_OK(tmp);
739            mr_free(tmp);
740        }
741
742        log_to_screen(_("Mondo has restored your system. Please remove the backup media and reboot."));
743        log_to_screen(_("Thank you for using Mondo Rescue."));
744        log_to_screen(_("Please visit our website at http://www.mondorescue.org for more information."));
745    }
746    g_I_have_just_nuked = TRUE;
747    return;
748}
749
750
751/**
752 * Restore the user's data automatically (no prompts), after a twenty-second
753 * warning period.
754 * @param bkpinfo The backup information structure. Most fields are used.
755 * @param mountlist The mountlist containing information about the user's partitions.
756 * @param raidlist The raidlist that goes with @p mountlist.
757 * @return 0 for success, or the number of errors encountered.
758 * @warning <b><i>THIS WILL ERASE ALL EXISTING DATA!</i></b>
759 */
760int
761nuke_mode(struct mountlist_itself *mountlist,
762          struct raidlist_itself *raidlist)
763{
764    int retval = 0;
765    int res = 0;
766    bool boot_loader_installed = FALSE;
767    char *tmp = NULL;
768    char tmpA[MAX_STR_LEN], tmpB[MAX_STR_LEN],
769        tmpC[MAX_STR_LEN];
770
771    assert(bkpinfo != NULL);
772    assert(mountlist != NULL);
773    assert(raidlist != NULL);
774
775    mr_msg(2, "nuke_mode --- starting");
776
777    get_cfg_file_from_archive_or_bust();
778    load_mountlist(mountlist, g_mountlist_fname);   // in case read_cfg_file_into_bkpinfo updated the mountlist
779#ifdef __FreeBSD__
780    tmp = call_program_and_get_last_line_of_output("cat /tmp/cmdline");
781#else
782    tmp = call_program_and_get_last_line_of_output("cat /proc/cmdline");
783#endif
784    if (strstr(tmp,"noresize")) {
785        mr_msg(2, "Not resizing mountlist.");
786    } else {
787        resize_mountlist_proportionately_to_suit_new_drives(mountlist);
788    }
789    if (!evaluate_mountlist(mountlist, tmpA, tmpB, tmpC)) {
790        mr_asprintf(&tmp,
791                _("Mountlist analyzed. Result: \"%s %s %s\" Switch to Interactive Mode?"),
792                tmpA, tmpB, tmpC);
793        if (ask_me_yes_or_no(tmp)) {
794            mr_free(tmp);
795            retval = interactive_mode(mountlist, raidlist);
796            call_me_after_the_nuke(retval);
797            return(retval);
798        } else {
799            mr_free(tmp);
800            fatal_error("Nuke Mode aborted. ");
801        }
802    }
803    save_mountlist_to_disk(mountlist, g_mountlist_fname);
804    mvaddstr_and_log_it(1, 30, _("Restoring Automatically"));
805    if (bkpinfo->differential) {
806        log_to_screen(_("Because this is a differential backup, disk"));
807        log_to_screen(_("partitioning and formatting will not take place."));
808        res = 0;
809    } else {
810        if (partition_table_contains_Compaq_diagnostic_partition
811            (mountlist)) {
812            offer_to_abort_because_Compaq_Proliants_suck();
813        } else {
814            twenty_seconds_til_yikes();
815            g_fprep = fopen("/tmp/prep.sh", "w");
816#ifdef __FreeBSD__
817            tmp = call_program_and_get_last_line_of_output("cat /tmp/cmdline");
818#else
819            tmp = call_program_and_get_last_line_of_output("cat /proc/cmdline");
820#endif
821            if (strstr(tmp,"nopart")) {
822                mr_msg(2,
823                        "Not partitioning drives due to 'nopart' option.");
824                res = 0;
825            } else {
826                res = partition_everything(mountlist);
827                if (res) {
828                    log_to_screen
829                        (_("Warning. Errors occurred during partitioning."));
830                    res = 0;
831                }
832            }
833            retval += res;
834            if (!res) {
835                log_to_screen(_("Preparing to format your disk(s)"));
836                sleep(1);
837                sync();
838                log_to_screen(_("Please wait. This may take a few minutes."));
839                res += format_everything(mountlist, FALSE, raidlist);
840            }
841            paranoid_fclose(g_fprep);
842        }
843    }
844    retval += res;
845    if (res) {
846        mvaddstr_and_log_it(g_currentY++,
847                            0,
848                            _("Failed to partition and/or format your hard drives."));
849
850        if (ask_me_yes_or_no(_("Try in interactive mode instead?"))) {
851            retval = interactive_mode(mountlist, raidlist);
852            call_me_after_the_nuke(retval);
853            return(retval);
854        } else
855            if (!ask_me_yes_or_no
856                (_("Would you like to try to proceed anyway?"))) {
857                return(retval);
858        }
859    }
860    retval = mount_all_devices(mountlist, TRUE);
861    if (retval) {
862        unmount_all_devices(mountlist);
863        log_to_screen
864            (_("Unable to mount all partitions. Sorry, I cannot proceed."));
865        return (retval);
866    }
867    iamhere("Restoring everything");
868    retval += restore_everything(NULL);
869    if (!run_boot_loader(FALSE)) {
870        mr_msg(1,
871                "Great! Boot loader was installed. No need for msg at end.");
872        boot_loader_installed = TRUE;
873    }
874    clean_blkid();
875    protect_against_braindead_sysadmins();
876    retval += unmount_all_devices(mountlist);
877    mvaddstr_and_log_it(g_currentY,
878                        0,
879                        _("Using tune2fs to identify your ext2,3 partitions"));
880
881    mr_asprintf(&tmp, "label-partitions-as-necessary %s < /tmp/fstab",
882            g_mountlist_fname);
883    res = run_program_and_log_output(tmp, TRUE);
884    mr_free(tmp);
885
886    if (res) {
887        log_to_screen(_("label-partitions-as-necessary returned an error"));
888        mvaddstr_and_log_it(g_currentY++, 74, _("Failed."));
889    } else {
890        mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
891    }
892    retval += res;
893
894    call_me_after_the_nuke(retval);
895    return (retval);
896}
897
898/**************************************************************************
899 *END_NUKE_MODE                                                           *
900 **************************************************************************/
901
902
903/**
904 * Restore the user's data (or a subset of it) to the live filesystem.
905 * This should not be called if we're booted from CD!
906 * @param bkpinfo The backup information structure. Most fields are used.
907 * @return 0 for success, or the number of errors encountered.
908 */
909int restore_to_live_filesystem()
910{
911    int retval = 0;
912
913    char *old_restpath = NULL;
914
915    struct mountlist_itself *mountlist = NULL;
916    struct raidlist_itself *raidlist = NULL;
917    struct s_node *filelist = NULL;
918
919    mr_msg(1, "restore_to_live_filesystem() - starting");
920    assert(bkpinfo != NULL);
921
922    mountlist = mr_malloc(sizeof(struct mountlist_itself));
923    raidlist = mr_malloc(sizeof(struct raidlist_itself));
924
925    strcpy(bkpinfo->restore_path, "/");
926    if (!g_restoring_live_from_cd && !g_restoring_live_from_nfs) {
927        popup_and_OK
928            (_("Please insert tape/CD/USB key, then hit 'OK' to continue."));
929        sleep(1);
930    }
931    if (!g_restoring_live_from_nfs) {
932        interactively_obtain_media_parameters_from_user(FALSE);
933    }
934    if (!bkpinfo->media_device) {
935        mr_msg(2, "Warning - failed to find media dev");
936    } else {
937        mr_msg(2, "bkpinfo->media_device = %s", bkpinfo->media_device);
938    }
939
940
941    mr_msg(2, "bkpinfo->isodir = %s", bkpinfo->isodir);
942
943    open_evalcall_form(_("Thinking..."));
944
945    get_cfg_file_from_archive_or_bust();
946    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
947    load_mountlist(mountlist, g_mountlist_fname);   // in case read_cfg_file_into_bkpinfo
948
949    close_evalcall_form();
950    retval = load_mountlist(mountlist, g_mountlist_fname);
951    load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
952
953    if (!g_restoring_live_from_nfs && (filelist = process_filelist_and_biggielist())) {
954        save_filelist(filelist, "/tmp/selected-files.txt");
955        mr_asprintf(&old_restpath,bkpinfo->restore_path);
956        if (popup_and_get_string(_("Restore path"),
957                                 _("Restore files to where? "),
958                                 bkpinfo->restore_path, MAX_STR_LEN)) {
959            iamhere("Restoring everything");
960            retval += restore_everything(filelist);
961        }
962        free_filelist(filelist);
963        strcpy(bkpinfo->restore_path, old_restpath);
964        mr_free(old_restpath);
965    } else {
966        retval += restore_everything(NULL);
967    }
968    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
969        mr_msg(2,
970                "Tape : I don't need to unmount or eject the CD-ROM.");
971    } else {
972        run_program_and_log_output("umount " MNT_CDROM, FALSE);
973        if (!bkpinfo->please_dont_eject) {
974            eject_device(bkpinfo->media_device);
975        }
976    }
977    run_program_and_log_output("umount " MNT_CDROM, FALSE);
978    if ((!bkpinfo->please_dont_eject) && (bkpinfo->media_device)) {
979        eject_device(bkpinfo->media_device);
980    }
981    mr_free(mountlist);
982    mr_free(raidlist);
983    return (retval);
984}
985
986/**************************************************************************
987 *END_RESTORE_TO_LIVE_FILESYSTEM                                          *
988 **************************************************************************/
989
990/* @} - end of restoreGroup */
991
992
993/**
994 * @addtogroup LLrestoreGroup
995 * @{
996 */
997/**
998 * Restore biggiefile @p bigfileno from the currently mounted CD.
999 * @param bkpinfo The backup information structure. Fields used:
1000 * - @c bkpinfo->backup_media_type
1001 * - @c bkpinfo->restore_path
1002 * @param bigfileno The biggiefile number (starting from 0) to restore.
1003 * @param filelist The node structure containing the list of files to restore.
1004 * If the biggiefile is not in this list, it will be skipped (return value will
1005 * still indicate success).
1006 * @return 0 for success (or skip), nonzero for failure.
1007 */
1008int
1009restore_a_biggiefile_from_CD(long bigfileno,
1010                             struct s_node *filelist,
1011                             char *pathname_of_last_file_restored)
1012{
1013    FILE *fin = NULL;
1014    FILE *fout = NULL;
1015    FILE *fbzip2 = NULL;
1016
1017    char *checksum = NULL;
1018    char *outfile_fname = NULL;
1019    char *tmp = NULL;
1020    char *bzip2_command = NULL;
1021    char *suffix = NULL;
1022    char *bigblk = NULL;
1023    int retval = 0;
1024    int finished = FALSE;
1025    long sliceno = 0L;
1026    long siz;
1027    char *ntfsprog_fifo = NULL;
1028    char *file_to_openout = NULL;
1029    struct s_filename_and_lstat_info biggiestruct;
1030    struct utimbuf the_utime_buf, *ubuf = NULL;
1031    bool use_ntfsprog_hack = FALSE;
1032    pid_t pid;
1033    int res = 0;
1034    int old_loglevel;
1035    struct s_node *node = NULL;
1036
1037    old_loglevel = mr_conf->log_level;
1038    ubuf = &the_utime_buf;
1039    assert(bkpinfo != NULL);
1040
1041    pathname_of_last_file_restored[0] = '\0';
1042    bigblk = mr_malloc(mr_conf->external_tape_blocksize);
1043
1044    if (!(fin = fopen(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""), "r"))) {
1045        log_to_screen("Cannot even open bigfile's info file");
1046        return (1);
1047    }
1048
1049    memset((void *) &biggiestruct, 0, sizeof(biggiestruct));
1050    if (fread((void *) &biggiestruct, 1, sizeof(biggiestruct), fin) <
1051        sizeof(biggiestruct)) {
1052        mr_msg(2, "Warning - unable to get biggiestruct of bigfile #%d",
1053                bigfileno + 1);
1054    }
1055    paranoid_fclose(fin);
1056
1057    mr_asprintf(&checksum, biggiestruct.checksum);
1058
1059    if (!checksum[0]) {
1060        mr_msg(3, "Warning - bigfile %ld does not have a checksum",
1061                bigfileno + 1);
1062    }
1063    mr_free(checksum);
1064
1065    if (!strncmp(biggiestruct.filename, "/dev/", 5))    // Whether NTFS or not :)
1066    {
1067        mr_asprintf(&outfile_fname, biggiestruct.filename);
1068    } else {
1069        mr_asprintf(&outfile_fname, "%s/%s", bkpinfo->restore_path,
1070                biggiestruct.filename);
1071    }
1072
1073    /* skip file if we have a selective restore subset & it doesn't match */
1074    if (filelist != NULL) {
1075        node = find_string_at_node(filelist, biggiestruct.filename);
1076        if (!node) {
1077            mr_msg(0, "Skipping %s (name isn't in filelist)",
1078                    biggiestruct.filename);
1079            return (0);
1080        } else if (!(node->selected)) {
1081            mr_msg(1, "Skipping %s (name isn't in biggielist subset)",
1082                    biggiestruct.filename);
1083            return (0);
1084        }
1085    }
1086    /* otherwise, continue */
1087
1088    mr_msg(1, "DEFINITELY restoring %s", biggiestruct.filename);
1089    if (biggiestruct.use_ntfsprog) {
1090        if (strncmp(biggiestruct.filename, "/dev/", 5)) {
1091            mr_msg(1,
1092                    "I was in error when I set biggiestruct.use_ntfsprog to TRUE.");
1093            mr_msg(1, "%s isn't even in /dev", biggiestruct.filename);
1094            biggiestruct.use_ntfsprog = FALSE;
1095        }
1096    }
1097
1098    if (biggiestruct.use_ntfsprog)  // if it's an NTFS device
1099    {
1100        mr_conf->log_level = 4;
1101        use_ntfsprog_hack = TRUE;
1102        mr_msg(2,
1103                "Calling ntfsclone in background because %s is an NTFS /dev entry",
1104                outfile_fname);
1105        mr_asprintf(&ntfsprog_fifo, "/tmp/%d.%d.000", (int) (random() % 32768),
1106                (int) (random() % 32768));
1107        mkfifo(ntfsprog_fifo, 0x770);
1108
1109        file_to_openout = ntfsprog_fifo;
1110        switch (pid = fork()) {
1111        case -1:
1112            fatal_error("Fork failure");
1113        case 0:
1114            mr_msg(3,
1115                    "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)",
1116                    biggiestruct.filename, ntfsprog_fifo);
1117            res =
1118                feed_outfrom_ntfsprog(biggiestruct.filename,
1119                                      ntfsprog_fifo);
1120            exit(res);
1121            break;
1122        default:
1123            mr_msg(3,
1124                    "feed_into_ntfsprog() called in background --- pid=%ld",
1125                    (long int) (pid));
1126        }
1127    } else {
1128        use_ntfsprog_hack = FALSE;
1129        file_to_openout = outfile_fname;
1130        if (!does_file_exist(outfile_fname))    // yes, it looks weird with the '!' but it's correct that way
1131        {
1132            make_hole_for_file(outfile_fname);
1133        }
1134    }
1135
1136    mr_msg(2, "Reassembling big file %ld (%s)", bigfileno + 1,
1137            outfile_fname);
1138
1139    /*
1140       last slice is zero-length and uncompressed; when we find it, we stop.
1141       We DON'T wait until there are no more slices; if we did that,
1142       We might stop at end of CD, not at last slice (which is 0-len and uncompd)
1143     */
1144
1145    strncpy(pathname_of_last_file_restored, biggiestruct.filename,
1146            MAX_STR_LEN - 1);
1147    pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0';
1148
1149    mr_msg(3, "file_to_openout = %s", file_to_openout);
1150    if (!(fout = fopen(file_to_openout, "w"))) {
1151        log_to_screen(_("Cannot openout file_to_openout - hard disk full?"));
1152        return (1);
1153    }
1154
1155    mr_free(ntfsprog_fifo);
1156    mr_msg(3, "Opened out to %s", outfile_fname);   // CD/DVD --> mondorestore --> ntfsclone --> hard disk itself
1157
1158    for (sliceno = 1, finished = FALSE; !finished;) {
1159        if (!does_file_exist
1160            (slice_fname(bigfileno, sliceno, ARCHIVES_PATH, ""))
1161            &&
1162            !does_file_exist(slice_fname
1163                             (bigfileno, sliceno, ARCHIVES_PATH, "lzo"))
1164            &&
1165            !does_file_exist(slice_fname
1166                             (bigfileno, sliceno, ARCHIVES_PATH, "gz"))
1167            &&
1168            !does_file_exist(slice_fname
1169                             (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) {
1170            mr_msg(3,
1171                    "Cannot find a data slice or terminator slice on CD %d",
1172                    g_current_media_number);
1173            g_current_media_number++;
1174            mr_msg(2, "Asking for %s #%d so that I may read slice #%ld\n",
1175                    media_descriptor_string(bkpinfo->backup_media_type),
1176                    g_current_media_number, sliceno);
1177            log_to_screen(_("Restoring from %s #%d"),
1178                    bkpinfo->backup_media_string,
1179                    g_current_media_number);
1180            insist_on_this_cd_number(g_current_media_number);
1181            log_to_screen(_("Continuing to restore."));
1182        } else {
1183            mr_asprintf(&tmp,
1184                   slice_fname(bigfileno, sliceno, ARCHIVES_PATH, ""));
1185            if (does_file_exist(tmp) && length_of_file(tmp) == 0) {
1186                mr_msg(2,
1187                        "End of bigfile # %ld (slice %ld is the terminator)",
1188                        bigfileno + 1, sliceno);
1189                finished = TRUE;
1190                mr_free(tmp);
1191                continue;
1192            } else {
1193                mr_free(tmp);
1194                if (does_file_exist
1195                    (slice_fname
1196                     (bigfileno, sliceno, ARCHIVES_PATH, "lzo"))) {
1197                    mr_asprintf(&bzip2_command, "lzop");
1198                    mr_asprintf(&suffix, "lzo");
1199                } else
1200                    if (does_file_exist
1201                        (slice_fname
1202                         (bigfileno, sliceno, ARCHIVES_PATH, "gz"))) {
1203                    mr_asprintf(&bzip2_command, "gzip");
1204                    mr_asprintf(&suffix, "gz");
1205                } else
1206                    if (does_file_exist
1207                        (slice_fname
1208                         (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) {
1209                    mr_asprintf(&bzip2_command, "bzip2");
1210                    mr_asprintf(&suffix, "bz2");
1211                } else
1212                    if (does_file_exist
1213                        (slice_fname
1214                         (bigfileno, sliceno, ARCHIVES_PATH, ""))) {
1215                    mr_asprintf(&bzip2_command, "");
1216                    mr_asprintf(&suffix, "");
1217                } else {
1218                    log_to_screen(_("OK, that's pretty fsck0red..."));
1219                    return (1);
1220                }
1221            }
1222            if (bzip2_command[0] != '\0') {
1223                mr_strcat(bzip2_command,
1224                        " -dc %s 2>> %s",
1225                        slice_fname(bigfileno, sliceno, ARCHIVES_PATH,
1226                                    suffix), MONDO_LOGFILE);
1227            } else {
1228                mr_free(bzip2_command);
1229                mr_asprintf(&bzip2_command, "cat %s 2>> %s",
1230                        slice_fname(bigfileno, sliceno, ARCHIVES_PATH,
1231                                    suffix), MONDO_LOGFILE);
1232            }
1233            mr_asprintf(&tmp, "Working on %s #%d, file #%ld, slice #%ld",
1234                    bkpinfo->backup_media_string,
1235                    g_current_media_number, bigfileno + 1, sliceno);
1236            mr_msg(2, tmp);
1237            if (!g_text_mode) {
1238                newtDrawRootText(0, g_noof_rows - 2, tmp);
1239                newtRefresh();
1240                update_progress_form(tmp);
1241            }
1242            mr_free(tmp);
1243
1244            if (!(fbzip2 = popen(bzip2_command, "r"))) {
1245                mr_free(bzip2_command);
1246                mr_free(suffix);
1247                fatal_error("Can't run popen command");
1248            }
1249            mr_free(bzip2_command);
1250            mr_free(suffix);
1251
1252            while (!feof(fbzip2)) {
1253                siz = fread(bigblk, 1, mr_conf->external_tape_blocksize, fbzip2);
1254                if (siz > 0) {
1255                    siz = fwrite(bigblk, 1, siz, fout);
1256                }
1257            }
1258            paranoid_pclose(fbzip2);
1259
1260            sliceno++;
1261            g_current_progress++;
1262        }
1263    }
1264    paranoid_fclose(fout);
1265    mr_conf->log_level = old_loglevel;
1266
1267    if (use_ntfsprog_hack) {
1268        mr_msg(3, "Waiting for ntfsclone to finish");
1269        mr_asprintf(&tmp,
1270                " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null");
1271        while (system(tmp) == 0) {
1272            sleep(1);
1273        }
1274        mr_free(tmp);
1275        log_it("OK, ntfsclone has really finished");
1276    }
1277
1278    if (strcmp(outfile_fname, "/dev/null")) {
1279        chown(outfile_fname, biggiestruct.properties.st_uid,
1280              biggiestruct.properties.st_gid);
1281        chmod(outfile_fname, biggiestruct.properties.st_mode);
1282        ubuf->actime = biggiestruct.properties.st_atime;
1283        ubuf->modtime = biggiestruct.properties.st_mtime;
1284        utime(outfile_fname, ubuf);
1285    }
1286    mr_free(outfile_fname);
1287    mr_free(bigblk);
1288
1289    return (retval);
1290}
1291
1292
1293/**************************************************************************
1294 *END_ RESTORE_A_BIGGIEFILE_FROM_CD                                       *
1295 **************************************************************************/
1296
1297
1298/**
1299 * Restore a biggiefile from the currently opened stream.
1300 * @param bkpinfo The backup information structure. Fields used:
1301 * - @c bkpinfo->restore_path
1302 * - @c bkpinfo->compression_tool
1303 * @param orig_bf_fname The original filename of the biggiefile.
1304 * @param biggiefile_number The number of the biggiefile (starting from 0).
1305 * @param filelist The node structure containing the list of files to be restored.
1306 * If @p orig_bf_fname is not in the list, it will be ignored.
1307 * @return 0 for success (or skip), nonzero for failure.
1308 */
1309int restore_a_biggiefile_from_stream(char *orig_bf_fname, long biggiefile_number, char *orig_checksum,  //UNUSED
1310                                     long long biggiefile_size, //UNUSED
1311                                     struct s_node *filelist,
1312                                     int use_ntfsprog,
1313                                     char *pathname_of_last_file_restored)
1314{
1315    FILE *pout = NULL;
1316    FILE *fin = NULL;
1317
1318  /** mallocs ********/
1319    char *tmp = NULL;
1320    char *tmp1 = NULL;
1321    char *command = NULL;
1322    char *outfile_fname = NULL;
1323    char *ntfsprog_fifo = NULL;
1324    char *file_to_openout = NULL;
1325
1326    struct s_node *node = NULL;
1327
1328    int old_loglevel = 0;
1329    long current_slice_number = 0;
1330    int retval = 0;
1331    int res = 0;
1332    int ctrl_chr = '\0';
1333    long long slice_siz = 0L;
1334    bool dummy_restore = FALSE;
1335    bool use_ntfsprog_hack = FALSE;
1336    pid_t pid;
1337    struct s_filename_and_lstat_info biggiestruct;
1338    struct utimbuf the_utime_buf, *ubuf = NULL;
1339    ubuf = &the_utime_buf;
1340
1341    old_loglevel = mr_conf->log_level;
1342    assert(bkpinfo != NULL);
1343    assert(orig_bf_fname != NULL);
1344    assert(orig_checksum != NULL);
1345
1346    pathname_of_last_file_restored[0] = '\0';
1347    if (use_ntfsprog == BLK_START_A_PIHBIGGIE) {
1348        use_ntfsprog = 1;
1349        mr_msg(1, "%s --- pih=YES", orig_bf_fname);
1350    } else if (use_ntfsprog == BLK_START_A_NORMBIGGIE) {
1351        use_ntfsprog = 0;
1352        mr_msg(1, "%s --- pih=NO", orig_bf_fname);
1353    } else {
1354        use_ntfsprog = 0;
1355        mr_msg(1, "%s --- pih=NO (weird marker though)", orig_bf_fname);
1356    }
1357
1358    strncpy(pathname_of_last_file_restored, orig_bf_fname,
1359            MAX_STR_LEN - 1);
1360    pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0';
1361
1362    /* open out to biggiefile to be restored (or /dev/null if biggiefile is not to be restored) */
1363
1364    if (filelist != NULL) {
1365        node = find_string_at_node(filelist, orig_bf_fname);
1366        if (!node) {
1367            dummy_restore = TRUE;
1368            mr_msg(1,
1369                    "Skipping big file %ld (%s) - not in biggielist subset",
1370                    biggiefile_number + 1, orig_bf_fname);
1371            pathname_of_last_file_restored[0] = '\0';
1372        } else if (!(node->selected)) {
1373            dummy_restore = TRUE;
1374            mr_msg(1, "Skipping %s (name isn't in biggielist subset)",
1375                    orig_bf_fname);
1376            pathname_of_last_file_restored[0] = '\0';
1377        }
1378    }
1379
1380    if (use_ntfsprog) {
1381        if (strncmp(orig_bf_fname, "/dev/", 5)) {
1382            mr_msg(1, "I was in error when I set use_ntfsprog to TRUE.");
1383            mr_msg(1, "%s isn't even in /dev", orig_bf_fname);
1384            use_ntfsprog = FALSE;
1385        }
1386    }
1387
1388    if (use_ntfsprog) {
1389        mr_conf->log_level = 4;
1390        mr_asprintf(&outfile_fname, orig_bf_fname);
1391        use_ntfsprog_hack = TRUE;
1392        mr_msg(2,
1393                "Calling ntfsclone in background because %s is a /dev entry",
1394                outfile_fname);
1395        mr_asprintf(&ntfsprog_fifo, "%s/%d.%d.000", 
1396                bkpinfo->tmpdir,
1397                (int) (random() % 32768),
1398                (int) (random() % 32768));
1399        mkfifo(ntfsprog_fifo, 0x770);
1400
1401        file_to_openout = ntfsprog_fifo;
1402        switch (pid = fork()) {
1403        case -1:
1404            fatal_error("Fork failure");
1405        case 0:
1406            mr_msg(3,
1407                    "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)",
1408                    outfile_fname, ntfsprog_fifo);
1409            res = feed_outfrom_ntfsprog(outfile_fname, ntfsprog_fifo);
1410            exit(res);
1411            break;
1412        default:
1413            mr_msg(3,
1414                    "feed_into_ntfsprog() called in background --- pid=%ld",
1415                    (long int) (pid));
1416        }
1417    } else {
1418        if (!strncmp(orig_bf_fname, "/dev/", 5))    // non-NTFS partition
1419        {
1420            mr_asprintf(&outfile_fname, orig_bf_fname);
1421        } else                  // biggiefile
1422        {
1423            mr_asprintf(&outfile_fname, "%s/%s", bkpinfo->restore_path,
1424                    orig_bf_fname);
1425        }
1426        use_ntfsprog_hack = FALSE;
1427        file_to_openout = outfile_fname;
1428        if (!does_file_exist(outfile_fname))    // yes, it looks weird with the '!' but it's correct that way
1429        {
1430            make_hole_for_file(outfile_fname);
1431        }
1432        mr_msg(2, "Reassembling big file %ld (%s)",
1433                biggiefile_number + 1, orig_bf_fname);
1434    }
1435
1436    if (dummy_restore) {
1437        mr_free(outfile_fname);
1438        mr_asprintf(&outfile_fname, "/dev/null");
1439    }
1440
1441    if (!bkpinfo->compression_tool) {
1442        mr_asprintf(&command, "cat > \"%s\"", file_to_openout);
1443    } else {
1444        mr_asprintf(&command, "%s -dc > \"%s\" 2>> %s", bkpinfo->compression_tool,
1445                file_to_openout, MONDO_LOGFILE);
1446    }
1447    mr_msg(3, "Pipe command = '%s'", command);
1448    mr_free(outfile_fname);
1449    mr_free(ntfsprog_fifo);
1450
1451    /* restore biggiefile, one slice at a time */
1452    if (!(pout = popen(command, "w"))) {
1453        fatal_error("Cannot pipe out");
1454    }
1455    mr_free(command);
1456
1457    malloc_string(tmp1);
1458    for (res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr);
1459         ctrl_chr != BLK_STOP_A_BIGGIE;
1460         res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr)) {
1461        if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1462            wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1463        }
1464        mr_asprintf(&tmp, "Working on file #%ld, slice #%ld    ",
1465                biggiefile_number + 1, current_slice_number);
1466        mr_msg(2, tmp);
1467        if (!g_text_mode) {
1468            newtDrawRootText(0, g_noof_rows - 2, tmp);
1469            newtRefresh();
1470        }
1471        mr_strip_spaces(tmp);
1472        update_progress_form(tmp);
1473        mr_free(tmp);
1474        if (current_slice_number == 0) {
1475            res =
1476                read_file_from_stream_to_file("/tmp/biggie-blah.txt",
1477                                              slice_siz);
1478            if (!(fin = fopen("/tmp/biggie-blah.txt", "r"))) {
1479                log_OS_error("blah blah");
1480            } else {
1481                if (fread
1482                    ((void *) &biggiestruct, 1, sizeof(biggiestruct),
1483                     fin) < sizeof(biggiestruct)) {
1484                    mr_msg(2,
1485                            "Warning - unable to get biggiestruct of bigfile #%d",
1486                            biggiefile_number + 1);
1487                }
1488                paranoid_fclose(fin);
1489            }
1490        } else {
1491            res =
1492                read_file_from_stream_to_stream(pout, slice_siz);
1493        }
1494        retval += res;
1495        res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr);
1496        if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
1497            wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
1498        }
1499        current_slice_number++;
1500        g_current_progress++;
1501    }
1502    mr_free(tmp1);
1503    paranoid_pclose(pout);
1504
1505    mr_msg(1, "pathname_of_last_file_restored is now %s",
1506            pathname_of_last_file_restored);
1507
1508    if (use_ntfsprog_hack) {
1509        mr_msg(3, "Waiting for ntfsclone to finish");
1510        mr_asprintf(&tmp,
1511                " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null");
1512        while (system(tmp) == 0) {
1513            sleep(1);
1514        }   
1515        mr_free(tmp);
1516        mr_msg(3, "OK, ntfsclone has really finished");
1517    }
1518
1519    mr_msg(3, "biggiestruct.filename = %s", biggiestruct.filename);
1520    mr_msg(3, "biggiestruct.checksum = %s", biggiestruct.checksum);
1521    if (strcmp(outfile_fname, "/dev/null")) {
1522        chmod(outfile_fname, biggiestruct.properties.st_mode);
1523        chown(outfile_fname, biggiestruct.properties.st_uid,
1524              biggiestruct.properties.st_gid);
1525        ubuf->actime = biggiestruct.properties.st_atime;
1526        ubuf->modtime = biggiestruct.properties.st_mtime;
1527        utime(outfile_fname, ubuf);
1528    }
1529
1530    mr_conf->log_level = old_loglevel;
1531    return (retval);
1532}
1533
1534/**************************************************************************
1535 *END_RESTORE_A_BIGGIEFILE_FROM_STREAM                                    *
1536 **************************************************************************/
1537
1538
1539/**
1540 * Restore @p tarball_fname from CD.
1541 * @param tarball_fname The filename of the tarball to restore (in /mnt/cdrom).
1542 * This will be used unmodified.
1543 * @param current_tarball_number The number (starting from 0) of the fileset
1544 * we're restoring now.
1545 * @param filelist The node structure containing the list of files to be
1546 * restored. If no file in the afioball is in this list, afio will still be
1547 * called, but nothing will be written.
1548 * @return 0 for success, nonzero for failure.
1549 */
1550int
1551restore_a_tarball_from_CD(char *tarball_fname,
1552                          long current_tarball_number,
1553                          struct s_node *filelist, struct s_bkpinfo *bkpinfo)
1554{
1555    int retval = 0;
1556    int res = 0;
1557    char *p = NULL;
1558
1559  /** malloc **/
1560    char *command = NULL;
1561    char *tmp = NULL;
1562    char *filelist_name = NULL;
1563    char *filelist_subset_fname = NULL;
1564    char *executable = NULL;
1565    char *temp_log = NULL;
1566    long matches = 0;
1567    bool use_star = FALSE;
1568    char *xattr_fname = NULL;
1569    char *acl_fname = NULL;
1570#ifdef __FreeBSD__
1571    long BUFSIZE=512L;
1572#else
1573    long BUFSIZE=(1024L*1024L)/mr_conf->external_tape_blocksize;
1574#endif
1575
1576
1577    assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
1578
1579    mr_msg(5, "Entering");
1580    use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE;
1581    mr_asprintf(&command, "mkdir -p %s/tmp", MNT_RESTORING);
1582    run_program_and_log_output(command, 9);
1583    mr_free(command);
1584
1585    mr_asprintf(&filelist_name, MNT_CDROM "/archives/filelist.%ld",
1586            current_tarball_number);
1587    if (length_of_file(filelist_name) <= 2) {
1588        mr_msg(2, "There are _zero_ files in filelist '%s'",
1589                filelist_name);
1590        mr_msg(2,
1591                "This is a bit silly (ask dev-team to fix mondo_makefilelist, please)");
1592        mr_msg(2,
1593                "but it's non-critical. It's cosmetic. Don't worry about it.");
1594        retval = 0;
1595        mr_msg(5, "Leaving");
1596        mr_free(filelist_name);
1597        return (retval);
1598    }
1599    if (count_lines_in_file(filelist_name) <= 0
1600        || length_of_file(tarball_fname) <= 0) {
1601        mr_msg(3, "length_of_file(%s) = %llu", tarball_fname,
1602                length_of_file(tarball_fname));
1603        log_to_screen(_("Unable to restore fileset #%ld (CD I/O error)"),
1604                current_tarball_number);
1605        retval = 1;
1606        mr_msg(5, "Leaving");
1607        mr_free(filelist_name);
1608        return (retval);
1609    }
1610
1611    if (filelist) {
1612        mr_asprintf(&filelist_subset_fname, "/tmp/filelist-subset-%ld.tmp",
1613                current_tarball_number);
1614        if ((matches =
1615             save_filelist_entries_in_common(filelist_name, filelist,
1616                                             filelist_subset_fname,
1617                                             use_star))
1618            <= 0) {
1619            mr_msg(1, "Skipping fileset %ld", current_tarball_number);
1620        } else {
1621            mr_msg(3, "Saved fileset %ld's subset to %s",
1622                    current_tarball_number, filelist_subset_fname);
1623        }
1624        log_to_screen("Tarball #%ld --- %ld matches",
1625                current_tarball_number, matches);
1626    }
1627    mr_free(filelist_name);
1628
1629    if (filelist == NULL || matches > 0) {
1630        if (g_getfattr) {
1631            mr_asprintf(&xattr_fname, XATTR_LIST_FNAME_RAW_SZ,
1632                MNT_CDROM "/archives", current_tarball_number);
1633        }
1634        if (g_getfacl) {
1635            mr_asprintf(&acl_fname, ACL_LIST_FNAME_RAW_SZ, MNT_CDROM "/archives",
1636                current_tarball_number);
1637        }
1638        if (strstr(tarball_fname, ".bz2")) {
1639            mr_asprintf(&executable, "-P bzip2 -Z");
1640        } else if (strstr(tarball_fname, ".gz")) {
1641            mr_asprintf(&executable, "-P gzip -Z");
1642        } else if (strstr(tarball_fname, ".lzo")) {
1643            mr_asprintf(&executable, "-P lzop -Z");
1644        }
1645
1646        if (executable == NULL) {
1647            mr_asprintf(&tmp, "which %s > /dev/null 2> /dev/null", executable);
1648            if (run_program_and_log_output(tmp, FALSE)) {
1649                log_to_screen
1650                    (_("(compare_a_tarball) Compression program not found - oh no!"));
1651                mr_free(tmp);
1652                mr_free(executable);
1653                mr_free(acl_fname);
1654                mr_free(xattr_fname);
1655                mr_free(filelist_subset_fname);
1656                paranoid_MR_finish(1);
1657            }
1658            mr_free(tmp);
1659        }
1660        if (use_star) {
1661            mr_asprintf(&command,
1662                    "star -x -force-remove -U " STAR_ACL_SZ
1663                    " errctl= file=%s", tarball_fname);
1664            if (strstr(tarball_fname, ".bz2")) {
1665                mr_strcat(command, " -bz");
1666            }
1667        } else {
1668            if (filelist_subset_fname != NULL) {
1669                mr_asprintf(&command,
1670                        "afio -i -M 8m -b %ld -c %ld %s -w '%s' %s",
1671                        mr_conf->external_tape_blocksize,
1672                        BUFSIZE, executable, filelist_subset_fname,
1673                        tarball_fname);
1674            } else {
1675                mr_asprintf(&command,
1676                        "afio -i -b %ld -c %ld -M 8m %s %s",
1677                        mr_conf->external_tape_blocksize,
1678                        BUFSIZE, executable, tarball_fname);
1679            }
1680        }
1681        mr_free(executable);
1682
1683        mr_asprintf(&temp_log, "/tmp/%d.%d", (int) (random() % 32768),
1684            (int) (random() % 32768));
1685
1686        mr_strcat(command, " 2>> %s >> %s", temp_log, temp_log);
1687        mr_msg(1, "command = '%s'", command);
1688        unlink(temp_log);
1689        res = system(command);
1690        if (res) {
1691            p = strstr(command, "-acl ");
1692            if (p) {
1693                p[0] = p[1] = p[2] = p[3] = ' ';
1694                mr_msg(1, "new command = '%s'", command);
1695                res = system(command);
1696            }
1697        }
1698        mr_free(command);
1699
1700        if (res && length_of_file(temp_log) < 5) {
1701            res = 0;
1702        }
1703
1704        if (g_getfattr) {
1705            mr_msg(1, "Setting fattr list %s", xattr_fname);
1706            if (length_of_file(xattr_fname) > 0) {
1707                res = set_fattr_list(filelist_subset_fname, xattr_fname);
1708                if (res) {
1709                    log_to_screen
1710                        ("Errors occurred while setting extended attributes");
1711                } else {
1712                    mr_msg(1, "I set xattr OK");
1713                }
1714                retval += res;
1715            }
1716        }
1717        if (g_getfacl) {
1718            mr_msg(1, "Setting acl list %s", acl_fname);
1719            if (length_of_file(acl_fname) > 0) {
1720                res = set_acl_list(filelist_subset_fname, acl_fname);
1721                if (res) {
1722                    log_to_screen
1723                        ("Errors occurred while setting access control lists");
1724                } else {
1725                    mr_msg(1, "I set ACL OK");
1726                }
1727                retval += res;
1728            }
1729        }
1730        if (retval) {
1731            mr_asprintf(&command, "cat %s >> %s", temp_log, MONDO_LOGFILE);
1732            system(command);
1733            mr_free(command);
1734            mr_msg(2, "Errors occurred while processing fileset #%d",
1735                    current_tarball_number);
1736        } else {
1737            mr_msg(2, "Fileset #%d processed OK", current_tarball_number);
1738        }
1739        unlink(xattr_fname);
1740        mr_free(xattr_fname);
1741        unlink(acl_fname);
1742        mr_free(acl_fname);
1743        unlink(temp_log);
1744        mr_free(temp_log);
1745    }
1746    if (does_file_exist("/PAUSE")) {
1747        popup_and_OK
1748            (_("Press ENTER to go on. Delete /PAUSE to stop these pauses."));
1749    }
1750    unlink(filelist_subset_fname);
1751    mr_free(filelist_subset_fname);
1752    mr_msg(5, "Leaving");
1753    return (retval);
1754}
1755
1756/**************************************************************************
1757 *END_RESTORE_A_TARBALL_FROM_CD                                           *
1758 **************************************************************************/
1759
1760
1761/**
1762 * Restore a tarball from the currently opened stream.
1763 * @param bkpinfo The backup information structure. Fields used:
1764 * - @c bkpinfo->backup_media_type
1765 * - @c bkpinfo->media_device
1766 * - @c bkpinfo->compression_tool
1767 * @param tarball_fname The filename of the afioball to restore.
1768 * @param current_tarball_number The number (starting from 0) of the fileset
1769 * we're restoring now.
1770 * @param filelist The node structure containing the list of files to be
1771 * restored. If no file in the afioball is in this list, afio will still be
1772 * called, but nothing will be written.
1773 * @param size The size (in @b bytes) of the afioball.
1774 * @return 0 for success, nonzero for failure.
1775 */
1776int
1777restore_a_tarball_from_stream(char *tarball_fname,
1778                              long current_tarball_number,
1779                              struct s_node *filelist,
1780                              long long size, char *xattr_fname,
1781                              char *acl_fname)
1782{
1783    int retval = 0;
1784    int res = 0;
1785
1786  /** malloc add ***/
1787    char *command = NULL;
1788    char *afio_fname = NULL;
1789    char *filelist_fname = NULL;
1790    char *filelist_subset_fname = NULL;
1791    char *executable = NULL;
1792    long matches = 0;
1793    bool restore_this_fileset = FALSE;
1794    bool use_star = FALSE;
1795
1796    assert(bkpinfo != NULL);
1797    assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
1798    /* to do it with a file... */
1799    use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE;
1800    mr_msg(2, "Restoring from fileset #%ld (%ld KB) on %s #%d",
1801            current_tarball_number, (long) size >> 10,
1802            bkpinfo->backup_media_string,
1803            g_current_media_number);
1804    run_program_and_log_output("mkdir -p " MNT_RESTORING "/tmp", FALSE);
1805
1806  /****************************************************************************
1807   * Use RAMDISK's /tmp; saves time; oh wait, it's too small                  *
1808   * Well, pipe from tape to afio, then; oh wait, can't do that either: bug   *
1809   * in afio or someting; oh darn.. OK, use tmpfs :-)                         *
1810   ****************************************************************************/
1811    mr_asprintf(&afio_fname, "/tmp/tmpfs/archive.tmp.%ld",
1812            current_tarball_number);
1813    mr_asprintf(&filelist_fname, "%s/filelist.%ld", bkpinfo->tmpdir,
1814            current_tarball_number);
1815    mr_asprintf(&filelist_subset_fname, "%s/filelist-subset-%ld.tmp",
1816            bkpinfo->tmpdir, current_tarball_number);
1817    res = read_file_from_stream_to_file(afio_fname, size);
1818    if (strstr(tarball_fname, ".star")) {
1819        bkpinfo->use_star = TRUE;
1820    }
1821    if (res) {
1822        mr_msg(1, "Warning - error reading afioball from tape");
1823    }
1824    if (bkpinfo->compression_level != 0) {
1825        if (bkpinfo->use_star) {
1826            mr_asprintf(&executable, " -bz");
1827        } else {
1828            mr_asprintf(&executable, "-P %s -Z", bkpinfo->compression_tool);
1829        }
1830    }
1831
1832    if (!filelist)              // if unconditional restore then restore entire fileset
1833    {
1834        restore_this_fileset = TRUE;
1835    } else                      // If restoring selectively then get TOC from tarball
1836    {
1837        if (strstr(tarball_fname, ".star.")) {
1838            use_star = TRUE;
1839            mr_asprintf(&command, "star -t file=%s %s", afio_fname, executable);
1840        } else {
1841            use_star = FALSE;
1842            mr_asprintf(&command, "afio -t -M 8m -b %ld %s %s", mr_conf->external_tape_blocksize,
1843                    executable, afio_fname);
1844        }
1845        mr_strcat(command, " > %s 2>> %s", filelist_fname, MONDO_LOGFILE);
1846        mr_msg(1, "command = %s", command);
1847        if (system(command)) {
1848            mr_msg(4, "Warning - error occurred while retrieving TOC");
1849        }
1850        mr_free(command);
1851
1852        if ((matches =
1853             save_filelist_entries_in_common(filelist_fname, filelist,
1854                                             filelist_subset_fname,
1855                                             use_star))
1856            <= 0 || length_of_file(filelist_subset_fname) < 2) {
1857            if (length_of_file(filelist_subset_fname) < 2) {
1858                mr_msg(1, "No matches found in fileset %ld",
1859                        current_tarball_number);
1860            }
1861            mr_msg(2, "Skipping fileset %ld", current_tarball_number);
1862            restore_this_fileset = FALSE;
1863        } else {
1864            mr_msg(5, "%ld matches. Saved fileset %ld's subset to %s",
1865                    matches, current_tarball_number,
1866                    filelist_subset_fname);
1867            restore_this_fileset = TRUE;
1868        }
1869    }
1870    unlink(filelist_fname);
1871    mr_free(filelist_fname);
1872
1873// Concoct the call to star/afio to restore files
1874    if (strstr(tarball_fname, ".star.")) {
1875        // star
1876        if (filelist) {
1877            mr_asprintf(&command, "star -x file=%s %s list=%s 2>> %s", afio_fname, executable, filelist_subset_fname, MONDO_LOGFILE);
1878        } else {
1879            mr_asprintf(&command, "star -x file=%s %s 2>> %s", afio_fname, executable, MONDO_LOGFILE);
1880        }
1881    } else {
1882        // afio
1883        if (filelist) {
1884            mr_asprintf(&command, "afio -i -M 8m -b %ld %s -w %s %s 2>> %s", mr_conf->external_tape_blocksize, executable, filelist_subset_fname, afio_fname, MONDO_LOGFILE);
1885        } else {
1886            mr_asprintf(&command, "afio -i -M 8m -b %ld %s %s 2>> %s", mr_conf->external_tape_blocksize, executable, afio_fname, MONDO_LOGFILE);
1887        }
1888    }
1889    mr_free(executable);
1890
1891    // Call if IF there are files to restore (selectively/unconditionally)
1892    if (restore_this_fileset) {
1893        mr_msg(1, "Calling command='%s'", command);
1894        paranoid_system(command);
1895
1896        if (g_getfattr) {
1897            iamhere("Restoring xattr stuff");
1898            res = set_fattr_list(filelist_subset_fname, xattr_fname);
1899            if (res) {
1900                mr_msg(1, "Errors occurred while setting xattr");
1901            } else {
1902                mr_msg(1, "I set xattr OK");
1903            }
1904            retval += res;
1905        }
1906
1907        if (g_getfacl) {
1908            iamhere("Restoring acl stuff");
1909            res = set_acl_list(filelist_subset_fname, acl_fname);
1910            if (res) {
1911                mr_msg(1, "Errors occurred while setting ACL");
1912            } else {
1913                mr_msg(1, "I set ACL OK");
1914            }
1915            retval += res;
1916        }
1917
1918    } else {
1919        mr_msg(1, "NOT CALLING '%s'", command);
1920    }
1921    mr_free(command);
1922
1923    if (does_file_exist("/PAUSE") && current_tarball_number >= 50) {
1924        log_to_screen(_("Paused after set %ld"), current_tarball_number);
1925        popup_and_OK(_("Pausing. Press ENTER to continue."));
1926    }
1927
1928    unlink(filelist_subset_fname);
1929    unlink(afio_fname);
1930
1931    mr_free(filelist_subset_fname);
1932    mr_free(afio_fname);
1933    return (retval);
1934}
1935
1936/**************************************************************************
1937 *END_RESTORE_A_TARBALL_FROM_STREAM                                       *
1938 **************************************************************************/
1939
1940
1941/**
1942 * Restore all biggiefiles from all media in this CD backup.
1943 * The CD with the last afioball should be currently mounted.
1944 * @param bkpinfo The backup information structure. @c backup_media_type is the
1945 * only field used in this function.
1946 * @param filelist The node structure containing the list of files to be
1947 * restored. If a prospective biggiefile is not in this list, it will be ignored.
1948 * @return 0 for success, nonzero for failure.
1949 */
1950int
1951restore_all_biggiefiles_from_CD(struct s_node *filelist)
1952{
1953    int retval = 0;
1954    int res = 0;
1955    long noof_biggiefiles = 0L, bigfileno = 0L, total_slices = 0L;
1956    char *tmp = NULL;
1957    char *tmp1 = NULL;
1958    bool just_changed_cds = FALSE, finished = FALSE;
1959    char *xattr_fname = NULL;
1960    char *acl_fname = NULL;
1961    char *biggies_whose_EXATs_we_should_set = NULL; // EXtended ATtributes
1962    char *pathname_of_last_biggie_restored = NULL;
1963    FILE *fbw = NULL;
1964
1965    malloc_string(tmp1);
1966    malloc_string(pathname_of_last_biggie_restored);
1967    assert(bkpinfo != NULL);
1968
1969    mr_asprintf(&biggies_whose_EXATs_we_should_set,
1970            "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir);
1971    if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) {
1972        mr_msg(1, "Warning - cannot openout %s",
1973                biggies_whose_EXATs_we_should_set);
1974    }
1975
1976    read_cfg_var(g_mondo_cfg_file, "total-slices", tmp1);
1977    total_slices = atol(tmp1);
1978    mr_free(tmp1);
1979
1980    mr_asprintf(&tmp, _("Reassembling large files      "));
1981    mvaddstr_and_log_it(g_currentY, 0, tmp);
1982    mr_free(tmp);
1983
1984    if (length_of_file(BIGGIELIST) < 6) {
1985        mr_msg(1, "OK, no biggielist; not restoring biggiefiles");
1986        return (0);
1987    }
1988    noof_biggiefiles = count_lines_in_file(BIGGIELIST);
1989    if (noof_biggiefiles <= 0) {
1990        mr_msg(2,
1991                "OK, no biggiefiles in biggielist; not restoring biggiefiles");
1992        return (0);
1993    }
1994    mr_msg(2, "OK, there are %ld biggiefiles in the archives", noof_biggiefiles);
1995
1996    open_progress_form(_("Reassembling large files"),
1997                       _("I am now reassembling all the large files."),
1998                       _("Please wait. This may take some time."),
1999                       "", total_slices);
2000    for (bigfileno = 0 ; bigfileno < noof_biggiefiles ;) {
2001        mr_msg(2, "Thinking about restoring bigfile %ld", bigfileno + 1);
2002        if (!does_file_exist(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""))) {
2003            mr_msg(3,
2004                    "...but its first slice isn't on this CD. Perhaps this was a selective restore?");
2005            mr_msg(3, "Cannot find bigfile #%ld 's first slice on %s #%d",
2006                    bigfileno + 1,
2007                    bkpinfo->backup_media_string,
2008                    g_current_media_number);
2009            mr_msg(3, "Slicename would have been %s",
2010                    slice_fname(bigfileno, 0, ARCHIVES_PATH, ""));
2011            // I'm not positive 'just_changed_cds' is even necessary...
2012            if (just_changed_cds) {
2013                just_changed_cds = FALSE;
2014                mr_msg(3,
2015                        "I'll continue to scan this CD for bigfiles to be restored.");
2016            } else if (does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST")) {
2017                insist_on_this_cd_number(++g_current_media_number);
2018                log_to_screen(_("Restoring from %s #%d"),
2019                        media_descriptor_string(bkpinfo->backup_media_type),
2020                        g_current_media_number);
2021                just_changed_cds = TRUE;
2022            } else {
2023                /* That big file doesn't exist, but the followings may */
2024                /* So we need to continue looping */
2025                mr_msg(2, "There was no bigfile #%ld. That's OK.",
2026                    bigfileno + 1);
2027                mr_msg(2, "I'm going to stop restoring bigfiles now.");
2028                retval++;
2029                bigfileno++;
2030            }
2031        } else {
2032            just_changed_cds = FALSE;
2033            mr_asprintf(&tmp, _("Restoring big file %ld"), bigfileno + 1);
2034            update_progress_form(tmp);
2035            mr_free(tmp);
2036
2037            res =
2038                restore_a_biggiefile_from_CD(bigfileno, filelist, pathname_of_last_biggie_restored);
2039            iamhere(pathname_of_last_biggie_restored);
2040            if (fbw && pathname_of_last_biggie_restored[0]) {
2041                fprintf(fbw, "%s\n", pathname_of_last_biggie_restored);
2042            }
2043            retval += res;
2044            bigfileno++;
2045        }
2046    }
2047
2048    if (fbw) {
2049        fclose(fbw);
2050        if (g_getfattr) {
2051            mr_asprintf(&xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH);
2052            if (length_of_file(xattr_fname) > 0) {
2053                set_fattr_list(biggies_whose_EXATs_we_should_set, xattr_fname);
2054            }
2055        }
2056        if (g_getfacl) {
2057            mr_asprintf(&acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH);
2058            if (length_of_file(acl_fname) > 0) {
2059                set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname);
2060            }
2061        }
2062        mr_free(acl_fname);
2063        mr_free(xattr_fname);
2064    }
2065    mr_free(biggies_whose_EXATs_we_should_set);
2066
2067    if (does_file_exist("/PAUSE")) {
2068        popup_and_OK
2069            (_("Press ENTER to go on. Delete /PAUSE to stop these pauses."));
2070    }
2071    close_progress_form();
2072    if (retval) {
2073        mvaddstr_and_log_it(g_currentY++, 74, _("Errors."));
2074    } else {
2075        mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
2076    }
2077    mr_free(pathname_of_last_biggie_restored);
2078    return (retval);
2079}
2080
2081/**************************************************************************
2082 *END_RESTORE_ALL_BIGGIFILES_FROM_CD                                      *
2083 **************************************************************************/
2084
2085
2086/**
2087 * Restore all afioballs from all CDs in the backup.
2088 * The first CD should be inserted (if not, it will be asked for).
2089 * @param bkpinfo The backup information structure. @c backup_media_type is the
2090 * only field used in @e this function.
2091 * @param filelist The node structure containing the list of files to be
2092 * restored. If no file in some particular afioball is in this list, afio will
2093 * still be called for that fileset, but nothing will be written.
2094 * @return 0 for success, or the number of filesets that failed.
2095 */
2096int
2097restore_all_tarballs_from_CD(struct s_node *filelist)
2098{
2099    int retval = 0;
2100    int res = 0;
2101    int attempts = 0;
2102    long current_tarball_number = 0;
2103    long max_val = 0L;
2104  /**malloc ***/
2105    char *tmp = NULL;
2106    char *tmp1 = NULL;
2107    char *tarball_fname = NULL;
2108    char *progress_str = NULL;
2109    char *comment = NULL;
2110
2111    malloc_string(tmp1);
2112    malloc_string(tarball_fname);
2113    malloc_string(progress_str);
2114    malloc_string(comment);
2115
2116    assert(bkpinfo != NULL);
2117
2118    mvaddstr_and_log_it(g_currentY, 0, _("Restoring from archives"));
2119    mr_msg(2,
2120            "Insisting on 1st CD, so that I can have a look at LAST-FILELIST-NUMBER");
2121    if (g_current_media_number != 1) {
2122        mr_msg(3, "OK, that's jacked up.");
2123        g_current_media_number = 1;
2124    }
2125    insist_on_this_cd_number(g_current_media_number);
2126    read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp1);
2127    max_val = atol(tmp1) + 1;
2128    mr_free(tmp1);
2129
2130    mr_asprintf(&progress_str, _("Restoring from %s #%d"),
2131            bkpinfo->backup_media_string,
2132            g_current_media_number);
2133    log_to_screen(progress_str);
2134    open_progress_form(_("Restoring from archives"),
2135                       _("Restoring data from the archives."),
2136                       _("Please wait. This may take some time."),
2137                       progress_str, max_val);
2138    for (;;) {
2139        insist_on_this_cd_number(g_current_media_number);
2140        update_progress_form(progress_str);
2141        mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.bz2",
2142                current_tarball_number);
2143        if (!does_file_exist(tarball_fname)) {
2144            mr_free(tarball_fname);
2145            mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.gz",
2146                    current_tarball_number);
2147        }
2148        if (!does_file_exist(tarball_fname)) {
2149            mr_free(tarball_fname);
2150            mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.lzo",
2151                current_tarball_number);
2152        }
2153        if (!does_file_exist(tarball_fname)) {
2154            mr_free(tarball_fname);
2155            mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.",
2156                    current_tarball_number);
2157        }
2158        if (!does_file_exist(tarball_fname)) {
2159            mr_free(tarball_fname);
2160            mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.star.bz2",
2161                    current_tarball_number);
2162        }
2163        if (!does_file_exist(tarball_fname)) {
2164            mr_free(tarball_fname);
2165            mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.star.",
2166                    current_tarball_number);
2167        }
2168        if (!does_file_exist(tarball_fname)) {
2169            mr_free(tarball_fname);
2170            if (current_tarball_number == 0) {
2171                log_to_screen
2172                    (_("No tarballs. Strange. Maybe you only backed up freakin' big files?"));
2173                mr_free(progress_str);
2174                return (0);
2175            }
2176            if (!does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST")
2177                || system("find " MNT_CDROM
2178                          "/archives/slice* > /dev/null 2> /dev/null") ==
2179                0) {
2180                mr_free(tarball_fname);
2181                mr_free(progress_str);
2182                break;
2183            }
2184            g_current_media_number++;
2185            mr_free(progress_str);
2186
2187            mr_asprintf(&progress_str, _("Restoring from %s #%d"),
2188                    bkpinfo->backup_media_string,
2189                    g_current_media_number);
2190            log_to_screen(progress_str);
2191        } else {
2192            mr_free(progress_str);
2193            mr_asprintf(&progress_str,
2194                    _("Restoring from fileset #%ld on %s #%d"),
2195                    current_tarball_number,
2196                    bkpinfo->backup_media_string,
2197                    g_current_media_number);
2198            for (res = 999, attempts = 0; attempts < 3 && res != 0;
2199                 attempts++) {
2200                res =
2201                    restore_a_tarball_from_CD(tarball_fname,
2202                                              current_tarball_number,
2203                                              filelist, bkpinfo);
2204            }
2205            mr_asprintf(&tmp, _("%s #%d, fileset #%ld - restore "),
2206                    media_descriptor_string(bkpinfo->backup_media_type),
2207                    g_current_media_number, current_tarball_number);
2208            if (res) {
2209                mr_strcat(tmp, _("reported errors"));
2210            } else {
2211                mr_strcat(tmp, _("succeeded"));
2212            }
2213            if (attempts > 1) {
2214                mr_strcat(tmp, _(" (%d attempts) - review logs"), attempts);
2215            }
2216            if (attempts > 1) {
2217                log_to_screen(tmp);
2218            }
2219            mr_free(tmp);
2220
2221            retval += res;
2222            current_tarball_number++;
2223            g_current_progress++;
2224        }
2225        mr_free(tarball_fname);
2226    }
2227    mr_free(progress_str);
2228    close_progress_form();
2229
2230    if (retval) {
2231        mvaddstr_and_log_it(g_currentY++, 74, _("Errors."));
2232    } else {
2233        mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
2234    }
2235    return (retval);
2236}
2237
2238/**************************************************************************
2239 *END_RESTORE_ALL_TARBALLS_FROM_CD                                        *
2240 **************************************************************************/
2241
2242
2243/**
2244 * Restore all biggiefiles from the currently opened stream.
2245 * @param bkpinfo The backup information structure. Passed to other functions.
2246 * @param filelist The node structure containing the list of files to be
2247 * restored. If a prospective biggiefile is not in the list, it will be ignored.
2248 * @return 0 for success, or the number of biggiefiles that failed.
2249 */
2250int
2251restore_all_biggiefiles_from_stream(struct s_node *filelist)
2252{
2253    long noof_biggiefiles = 0L;
2254    long current_bigfile_number = 0L;
2255    long total_slices = 0L;
2256
2257    int retval = 0;
2258    int res = 0;
2259    int ctrl_chr = 0;
2260
2261  /** malloc add ****/
2262    char *tmp = NULL;
2263    char *biggie_fname = NULL;
2264    char *biggie_cksum = NULL;
2265    char *xattr_fname = NULL;
2266    char *acl_fname = NULL;
2267    char *pathname_of_last_biggie_restored = NULL;
2268    char *biggies_whose_EXATs_we_should_set = NULL; // EXtended ATtributes
2269    long long biggie_size = (long long)0;
2270    FILE *fbw;
2271
2272    assert(bkpinfo != NULL);
2273
2274    malloc_string(tmp);
2275    malloc_string(biggie_fname);
2276    malloc_string(biggie_cksum);
2277    malloc_string(pathname_of_last_biggie_restored);
2278    read_cfg_var(g_mondo_cfg_file, "total-slices", tmp);
2279    total_slices = atol(tmp);
2280    mr_free(tmp);
2281
2282    mr_asprintf(&tmp, "Reassembling large files      ");
2283    if (g_getfattr) {
2284        mr_asprintf(&xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2285    }
2286    if (g_getfacl) {
2287        mr_asprintf(&acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2288    }
2289    mvaddstr_and_log_it(g_currentY, 0, tmp);
2290    mr_free(tmp);
2291
2292    mr_asprintf(&biggies_whose_EXATs_we_should_set,
2293            "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir);
2294    if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) {
2295        mr_msg(1, "Warning - cannot openout %s",
2296                biggies_whose_EXATs_we_should_set);
2297    }
2298    // get xattr and acl files if they're there
2299    res =
2300        read_header_block_from_stream(&biggie_size, biggie_fname,
2301                                      &ctrl_chr);
2302    if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
2303        res =
2304            read_EXAT_files_from_tape(&biggie_size, biggie_fname,
2305                                      &ctrl_chr, xattr_fname, acl_fname);
2306    }
2307
2308    noof_biggiefiles = atol(biggie_fname);
2309    mr_msg(2, "OK, there are %ld biggiefiles in the archives",
2310            noof_biggiefiles);
2311    open_progress_form(_("Reassembling large files"),
2312                       _("I am now reassembling all the large files."),
2313                       _("Please wait. This may take some time."),
2314                       "", total_slices);
2315
2316    for (res =
2317         read_header_block_from_stream(&biggie_size, biggie_fname,
2318                                       &ctrl_chr);
2319         ctrl_chr != BLK_STOP_BIGGIEFILES;
2320         res =
2321         read_header_block_from_stream(&biggie_size, biggie_fname,
2322                                       &ctrl_chr)) {
2323        if (ctrl_chr != BLK_START_A_NORMBIGGIE
2324            && ctrl_chr != BLK_START_A_PIHBIGGIE) {
2325            wrong_marker(BLK_START_A_NORMBIGGIE, ctrl_chr);
2326        }
2327        /* BERLIOS: useless
2328        p = strrchr(biggie_fname, '/');
2329        if (!p) {
2330            p = biggie_fname;
2331        } else {
2332            p++;
2333        }
2334        */
2335        mr_asprintf(&tmp, _("Restoring big file %ld (%lld K)"),
2336                current_bigfile_number + 1, biggie_size / 1024);
2337        update_progress_form(tmp);
2338        mr_free(tmp);
2339
2340        res = restore_a_biggiefile_from_stream(biggie_fname,
2341                                               current_bigfile_number,
2342                                               biggie_cksum,
2343                                               biggie_size,
2344                                               filelist, ctrl_chr,
2345                                               pathname_of_last_biggie_restored);
2346        mr_msg(1, "I believe I have restored %s",
2347                pathname_of_last_biggie_restored);
2348        if (fbw && pathname_of_last_biggie_restored[0]) {
2349            fprintf(fbw, "%s\n", pathname_of_last_biggie_restored);
2350        }
2351        mr_free(pathname_of_last_biggie_restored);
2352
2353        retval += res;
2354        current_bigfile_number++;
2355
2356    }
2357    if (current_bigfile_number != noof_biggiefiles
2358        && noof_biggiefiles != 0) {
2359        mr_msg(1, "Warning - bigfileno=%ld but noof_biggiefiles=%ld\n",
2360                current_bigfile_number, noof_biggiefiles);
2361    } else {
2362        mr_msg(1, "%ld biggiefiles in biggielist.txt; %ld biggiefiles processed today.",
2363                noof_biggiefiles, current_bigfile_number);
2364    }
2365
2366    if (fbw) {
2367        fclose(fbw);
2368        if (length_of_file(biggies_whose_EXATs_we_should_set) > 2) {
2369            iamhere("Setting biggie-EXATs");
2370            if (g_getfattr) {
2371                if (length_of_file(xattr_fname) > 0) {
2372                    mr_msg(1, "set_fattr_List(%s,%s)",
2373                        biggies_whose_EXATs_we_should_set, xattr_fname);
2374                    set_fattr_list(biggies_whose_EXATs_we_should_set,
2375                               xattr_fname);
2376                }
2377            }
2378            if (g_getfacl) {
2379                if (length_of_file(acl_fname) > 0) {
2380                    mr_msg(1, "set_acl_list(%s,%s)",
2381                            biggies_whose_EXATs_we_should_set, acl_fname);
2382                    set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname);
2383                }
2384            }
2385        } else {
2386            iamhere
2387                ("No biggiefiles selected. So, no biggie-EXATs to set.");
2388        }
2389    }
2390    mr_free(xattr_fname);
2391    mr_free(acl_fname);
2392    mr_free(biggies_whose_EXATs_we_should_set);
2393
2394    if (does_file_exist("/PAUSE")) {
2395        popup_and_OK
2396            (_("Press ENTER to go on. Delete /PAUSE to stop these pauses."));
2397    }
2398
2399    close_progress_form();
2400    if (retval) {
2401        mvaddstr_and_log_it(g_currentY++, 74, _("Errors."));
2402    } else {
2403        mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
2404    }
2405    mr_free(biggie_fname);
2406    mr_free(biggie_cksum);
2407    return (retval);
2408}
2409
2410/**************************************************************************
2411 *END_RESTORE_ALL_BIGGIEFILES_FROM_STREAM                                 *
2412 **************************************************************************/
2413
2414
2415/**
2416 * Restore all afioballs from the currently opened tape stream.
2417 * @param bkpinfo The backup information structure. Fields used:
2418 * - @c bkpinfo->backup_media_type
2419 * - @c bkpinfo->restore_path
2420 * @param filelist The node structure containing the list of files to be
2421 * restored. If no file in an afioball is in this list, afio will still be
2422 * called for that fileset, but nothing will be written.
2423 * @return 0 for success, or the number of filesets that failed.
2424 */
2425int
2426restore_all_tarballs_from_stream(struct s_node *filelist)
2427{
2428    int retval = 0;
2429    int res = 0;
2430    long current_afioball_number = 0;
2431    int ctrl_chr = 0;
2432    long max_val = 0L /*, total_noof_files */ ;
2433
2434  /** malloc **/
2435    char *tmp = NULL;
2436    char *progress_str = NULL;
2437    char *tmp_fname = NULL;
2438    char *xattr_fname = NULL;
2439    char *acl_fname = NULL;
2440
2441    long long tmp_size = 0L;
2442
2443    malloc_string(tmp_fname);
2444    malloc_string(tmp);
2445    assert(bkpinfo != NULL);
2446    mvaddstr_and_log_it(g_currentY, 0, _("Restoring from archives"));
2447    read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp);
2448    max_val = atol(tmp) + 1;
2449    mr_free(tmp);
2450
2451    chdir(bkpinfo->restore_path);   /* I don't know why this is needed _here_ but it seems to be. -HR, 02/04/2002 */
2452
2453    run_program_and_log_output("pwd", 5);
2454
2455    mr_asprintf(&progress_str, _("Restoring from media #%d"),
2456            g_current_media_number);
2457    log_to_screen(progress_str);
2458    open_progress_form(_("Restoring from archives"),
2459                       _("Restoring data from the archives."),
2460                       _("Please wait. This may take some time."),
2461                       progress_str, max_val);
2462
2463    mr_msg(3, "hey");
2464
2465    res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
2466    if (res) {
2467        mr_msg(2, "Warning - error reading afioball from tape");
2468    }
2469    retval += res;
2470    if (ctrl_chr != BLK_START_AFIOBALLS) {
2471        wrong_marker(BLK_START_AFIOBALLS, ctrl_chr);
2472    }
2473    mr_msg(2, "ho");
2474    res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
2475    while (ctrl_chr != BLK_STOP_AFIOBALLS) {
2476        update_progress_form(progress_str);
2477        if (g_getfattr) {
2478            mr_asprintf(&xattr_fname, "%s/xattr-subset-%ld.tmp", bkpinfo->tmpdir,
2479                current_afioball_number);
2480            unlink(xattr_fname);
2481        }
2482        if (g_getfacl) {
2483            mr_asprintf(&acl_fname, "%s/acl-subset-%ld.tmp", bkpinfo->tmpdir,
2484                current_afioball_number);
2485            unlink(acl_fname);
2486        }
2487        if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
2488            iamhere("Reading EXAT files from tape");
2489            res =
2490                read_EXAT_files_from_tape(&tmp_size, tmp_fname,
2491                                          &ctrl_chr, xattr_fname,
2492                                          acl_fname);
2493        }
2494        if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
2495            wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
2496        }
2497        /* BERLIOS: useless ?
2498        mr_asprintf(&tmp,
2499                _("Restoring from fileset #%ld (name=%s, size=%ld K)"),
2500                current_afioball_number, tmp_fname, (long) tmp_size >> 10);
2501                */
2502        res =
2503            restore_a_tarball_from_stream(tmp_fname,
2504                                          current_afioball_number,
2505                                          filelist, tmp_size, xattr_fname,
2506                                          acl_fname);
2507        retval += res;
2508        if (res) {
2509            log_to_screen("Fileset %ld - errors occurred",
2510                    current_afioball_number);
2511        }
2512        res =
2513            read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
2514        if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
2515            wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
2516        }
2517
2518        current_afioball_number++;
2519        g_current_progress++;
2520
2521        mr_free(progress_str);
2522        mr_asprintf(&progress_str, _("Restoring from fileset #%ld on %s #%d"),
2523                current_afioball_number,
2524                bkpinfo->backup_media_string,
2525                g_current_media_number);
2526        res =
2527            read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
2528        if (g_getfattr) {
2529            unlink(xattr_fname);
2530        }
2531        if (g_getfacl) {
2532            unlink(acl_fname);
2533        }
2534        mr_free(xattr_fname);
2535        mr_free(acl_fname);
2536    }                           // next
2537    mr_free(progress_str);
2538    mr_free(tmp_fname);
2539
2540    mr_msg(1, "All done with afioballs");
2541    close_progress_form();
2542    if (retval) {
2543        mvaddstr_and_log_it(g_currentY++, 74, _("Errors."));
2544    } else {
2545        mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
2546    }
2547    return (retval);
2548}
2549
2550/**************************************************************************
2551 *END_ RESTORE_ALL_TARBALLS_FROM_STREAM                                   *
2552 **************************************************************************/
2553
2554/* @} - end of LLrestoreGroup */
2555
2556
2557/**
2558 * Restore all files in @p filelist.
2559 * @param bkpinfo The backup information structure. Most fields are used.
2560 * @param filelist The node structure containing the list of files to be
2561 * restored.
2562 * @return 0 for success, or the number of afioballs and biggiefiles that failed.
2563 * @ingroup restoreGroup
2564 */
2565int restore_everything(struct s_node *filelist)
2566{
2567    int resA;
2568    int resB;
2569
2570  /** mallco ***/
2571    char *cwd = NULL;
2572    char *newpath = NULL;
2573    char *tmp = NULL;
2574    assert(bkpinfo != NULL);
2575
2576    malloc_string(cwd);
2577    malloc_string(newpath);
2578    mr_msg(2, "restore_everything() --- starting");
2579    g_current_media_number = 1;
2580    /* BERLIOS: should test return value, or better change the function */
2581    getcwd(cwd, MAX_STR_LEN - 1);
2582    mr_asprintf(&tmp, "mkdir -p %s", bkpinfo->restore_path);
2583    run_program_and_log_output(tmp, FALSE);
2584    mr_free(tmp);
2585
2586    mr_msg(1, "Changing dir to %s", bkpinfo->restore_path);
2587    chdir(bkpinfo->restore_path);
2588    /* BERLIOS: should test return value, or better change the function */
2589    getcwd(newpath, MAX_STR_LEN - 1);
2590    mr_msg(1, "path is now %s", newpath);
2591    mr_msg(1, "restoring everything");
2592    if (!find_home_of_exe("petris") && !g_text_mode) {
2593        newtDrawRootText(0, g_noof_rows - 2,
2594                         _("Press ALT-<left cursor> twice to play Petris :-) "));
2595        newtRefresh();
2596    }
2597    mvaddstr_and_log_it(g_currentY, 0, _("Preparing to read your archives"));
2598    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2599        mount_media();
2600        mvaddstr_and_log_it(g_currentY++, 0,
2601                            _("Restoring OS and data from streaming media"));
2602        if (bkpinfo->backup_media_type == cdstream) {
2603            openin_cdstream();
2604        } else {
2605            assert_string_is_neither_NULL_nor_zerolength(bkpinfo->media_device);
2606            openin_tape();
2607        }
2608        resA = restore_all_tarballs_from_stream(filelist);
2609        resB = restore_all_biggiefiles_from_stream(filelist);
2610        if (bkpinfo->backup_media_type == cdstream) {
2611            closein_cdstream();
2612        } else {
2613            closein_tape();
2614        }
2615    } else {
2616        mvaddstr_and_log_it(g_currentY++, 0,
2617                            _("Restoring OS and data from CD/USB   "));
2618        mount_media();
2619        resA = restore_all_tarballs_from_CD(filelist);
2620        resB = restore_all_biggiefiles_from_CD(filelist);
2621    }
2622    chdir(cwd);
2623    if (resA + resB) {
2624        log_to_screen(_("Errors occurred while data was being restored."));
2625    }
2626    if (length_of_file("/etc/raidtab") > 0) {
2627        mr_msg(2, "Copying local raidtab to restored filesystem");
2628        run_program_and_log_output("cp -f /etc/raidtab " MNT_RESTORING
2629                                   "/etc/raidtab", FALSE);
2630    }
2631    kill_petris();
2632    mr_msg(2, "restore_everything() --- leaving");
2633    mr_free(cwd);
2634    mr_free(newpath);
2635    return (resA + resB);
2636}
2637
2638/**************************************************************************
2639 *END_RESTORE_EVERYTHING                                                  *
2640 **************************************************************************/
2641
2642
2643/**
2644 * @brief Haha. You wish! (This function is not implemented :-)
2645 */
2646int
2647restore_live_from_monitas_server(char *monitas_device,
2648                                 char *restore_this_directory,
2649                                 char *restore_here)
2650     /* NB: bkpinfo hasn't been populated yet, except for ->tmp which is "/tmp" */
2651{
2652    FILE *fout;
2653    int retval = 0;
2654    int i;
2655    int j;
2656    struct mountlist_itself the_mountlist;
2657    static struct raidlist_itself the_raidlist;
2658  /** malloc **/
2659    char tmp[MAX_STR_LEN + 1];
2660    char command[MAX_STR_LEN + 1];
2661    char datablock[256 * 1024];
2662    char datadisks_fname[MAX_STR_LEN + 1];
2663    long k;
2664    long length;
2665    long long llt;
2666    struct s_node *filelist = NULL;
2667    assert(bkpinfo != NULL);
2668    assert_string_is_neither_NULL_nor_zerolength(monitas_device);
2669    assert(restore_this_directory != NULL);
2670    assert(restore_here != NULL);
2671
2672    sprintf(tmp, "restore_here = '%s'", restore_here);
2673
2674    mr_msg(2, tmp);
2675
2676    mr_msg(2, "restore_live_from_monitas_server() - starting");
2677    unlink("/tmp/mountlist.txt");
2678    unlink("/tmp/filelist.full");
2679    unlink("/tmp/biggielist.txt");
2680    if (restore_here[0] == '\0') {
2681        strcpy(bkpinfo->restore_path, MNT_RESTORING);
2682    } else {
2683        strcpy(bkpinfo->restore_path, restore_here);
2684    }
2685    mr_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI");
2686    sprintf(tmp, "FYI - data will be restored to %s",
2687            bkpinfo->restore_path);
2688    mr_msg(3, tmp);
2689    mr_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI");
2690    sprintf(datadisks_fname, "/tmp/mondorestore.datadisks.%d",
2691            (int) (random() % 32768));
2692    chdir(bkpinfo->tmpdir);
2693
2694    sprintf(command, "cat %s", monitas_device);
2695    g_tape_stream = popen(command, "r");    // for compatibility with openin_tape()
2696    if (!(fout = fopen(datadisks_fname, "w"))) {
2697        log_OS_error(datadisks_fname);
2698        return (1);
2699    }
2700    for (i = 0; i < 32; i++) {
2701        for (j = 0; j < 4; j++) {
2702            for (length = k = 0; length < 256 * 1024; length += k) {
2703                k = fread(datablock + length, 1, 256 * 1024 - length,
2704                          g_tape_stream);
2705            }
2706            fwrite(datablock, 1, length, fout);
2707            g_tape_posK += length;
2708        }
2709    }
2710    paranoid_fclose(fout);
2711    sprintf(command,
2712            "tar -zxvf %s ./tmp/mondo-restore.cfg ./tmp/mountlist.txt ./tmp/filelist.full ./tmp/biggielist.txt",
2713            datadisks_fname);
2714    run_program_and_log_output(command, 4);
2715    read_header_block_from_stream(&llt, tmp, &i);
2716    read_header_block_from_stream(&llt, tmp, &i);
2717
2718    unlink(datadisks_fname);
2719    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
2720    retval = load_mountlist(&the_mountlist, g_mountlist_fname); // in case read_cfg_file_into_bkpinfo   strcpy(bkpinfo->media_device, monitas_device);
2721
2722
2723    load_raidtab_into_raidlist(&the_raidlist, RAIDTAB_FNAME);
2724    iamhere("FIXME");
2725    fatal_error("This will fail");
2726    sprintf(command,
2727            "grep -E '^%s.*$' %s > %s",
2728            restore_this_directory, g_filelist_full, g_filelist_full);
2729    if (system(command)) {
2730        retval++;
2731        log_to_screen
2732            ("Error(s) occurred while processing filelist and wildcard");
2733    }
2734    iamhere("FIXME");
2735    fatal_error("This will fail");
2736    sprintf(command,
2737            "grep -E '^%s.*$' %s > %s",
2738            restore_this_directory, g_biggielist_txt, g_biggielist_txt);
2739    if (system(command)) {
2740        mr_msg(1,
2741                "Error(s) occurred while processing biggielist and wildcard");
2742    }
2743    sprintf(command, "touch %s", g_biggielist_txt);
2744    run_program_and_log_output(command, FALSE);
2745//  filelist = load_filelist(g_filelist_restthese);  // FIXME --- this probably doesn't work because it doesn't include the biggiefiles
2746    retval += restore_everything(filelist);
2747    free_filelist(filelist);
2748    mr_msg(2, "--------End of restore_live_from_monitas_server--------");
2749    return (retval);
2750}
2751
2752/**************************************************************************
2753 *END_RESTORE_LIVE_FROM_MONITAS_SERVER                                    *
2754 **************************************************************************/
2755
2756
2757
2758
2759extern void wait_until_software_raids_are_prepped(int);
2760
2761char which_restore_mode(void);
2762
2763
2764/**
2765 * Log a "don't panic" message to the logfile.
2766 */
2767void welcome_to_mondorestore(void)
2768{
2769    mr_msg(0, "-------------- Mondo Restore v%s -------------", PACKAGE_VERSION);
2770    mr_msg(0,
2771            "DON'T PANIC! Mondorestore logs almost everything, so please ");
2772    mr_msg(0,
2773            "don't break out in a cold sweat just because you see a few  ");
2774    mr_msg(0,
2775            "error messages in the log. Read them; analyze them; see if  ");
2776    mr_msg(0,
2777            "they are significant; above all, verify your backups! Please");
2778    mr_msg(0,
2779            "attach a compressed copy of this log to any e-mail you send ");
2780    mr_msg(0,
2781            "to the Mondo mailing list when you are seeking technical    ");
2782    mr_msg(0,
2783            "support. Without it, we can't help you.            - DevTeam");
2784    mr_msg(0,
2785            "------------------------------------------------------------");
2786    mr_msg(0,
2787            "BTW, despite (or perhaps because of) the wealth of messages,");
2788    mr_msg(0,
2789            "some users are inclined to stop reading this log.  If Mondo ");
2790    mr_msg(0,
2791            "stopped for some reason, chances are it's detailed here.    ");
2792    mr_msg(0,
2793            "More than likely there's a message near the end of this     ");
2794    mr_msg(0,
2795            "log that will tell you what is wrong.  Please read it!      ");
2796    mr_msg(0,
2797            "------------------------------------------------------------");
2798}
2799
2800
2801/**
2802 * Restore the user's data.
2803 * What did you think it did, anyway? :-)
2804 */
2805int main(int argc, char *argv[])
2806{
2807    FILE *fin = NULL;
2808    FILE *fout = NULL;
2809    int retval = 0;
2810    int res = 0;
2811    char *tmp = NULL;
2812
2813    struct mountlist_itself *mountlist = NULL;
2814    struct raidlist_itself *raidlist = NULL;
2815    struct s_node *filelist = NULL;
2816    char *a = NULL, *b = NULL;
2817    bool run_postnuke = FALSE;
2818
2819#ifdef ENABLE_NLS
2820    setlocale(LC_ALL, "");
2821    (void) textdomain("mondo");
2822#endif
2823
2824    /* Reference the right cleanup function for mr_exit */
2825    mr_cleanup = &mr_rs_cleanup;
2826
2827    if (getuid() != 0) {
2828        fprintf(stderr, _("Please run as root.\n"));
2829        mr_exit(127, NULL);
2830    }
2831    /* Conf file management */
2832    mr_conf = mr_malloc(sizeof(struct mr_rs_conf));
2833    mr_rs_reset_conf(mr_conf);
2834    bkpinfo = mr_malloc(sizeof(struct s_bkpinfo));
2835    reset_bkpinfo();
2836
2837    mr_conf->log_level = DEFAULT_MR_LOGLEVEL;
2838
2839/* Configure global variables */
2840#ifdef __FreeBSD__
2841    if (strstr
2842        (call_program_and_get_last_line_of_output("cat /tmp/cmdline"),
2843         "textonly"))
2844#else
2845    if (strstr
2846        (call_program_and_get_last_line_of_output("cat /proc/cmdline"),
2847         "textonly"))
2848#endif
2849    {
2850        g_text_mode = TRUE;
2851        mr_msg(1, "TEXTONLY MODE");
2852    } else {
2853        g_text_mode = FALSE;
2854    }                           // newt :-)
2855    mountlist = mr_malloc(sizeof(struct mountlist_itself));
2856    raidlist = mr_malloc(sizeof(struct raidlist_itself));
2857
2858    malloc_libmondo_global_strings();
2859
2860    sprintf(g_tmpfs_mountpt, "/tmp/tmpfs");
2861    make_hole_for_dir(g_tmpfs_mountpt);
2862    g_current_media_number = 1; // precaution
2863
2864    run_program_and_log_output("mkdir -p " MNT_CDROM, FALSE);
2865
2866    malloc_string(a);
2867    malloc_string(b);
2868    setup_MR_global_filenames();    // malloc() and set globals, using bkpinfo->tmpdir etc.
2869    bkpinfo->backup_media_type = none;  // in case boot disk was made for one backup type but user wants to restore from another backup type
2870    strcpy(bkpinfo->backup_media_string,"");
2871    bkpinfo->restore_data = TRUE;   // Well, yeah :-)
2872    if (am_I_in_disaster_recovery_mode()) {
2873        run_program_and_log_output("mount / -o remount,rw", 2);
2874    }                           // for b0rken distros
2875    g_main_pid = getpid();
2876    srandom((int) (time(NULL)));
2877    register_pid(getpid(), "mondo");
2878    set_signals(TRUE);
2879    g_kernel_version = get_kernel_version();
2880
2881    mr_msg(1, "FYI - g_mountlist_fname = %s", g_mountlist_fname);
2882    if (strlen(g_mountlist_fname) < 3) {
2883        fatal_error
2884            ("Serious error in malloc()'ing. Could be a bug in your glibc.");
2885    }
2886    mkdir(MNT_CDROM, 0x770);
2887    make_hole_for_dir(MONDO_CACHE);
2888
2889    /* Backup original mountlist.txt */
2890    mr_asprintf(&tmp, "%s.orig", g_mountlist_fname);
2891    if (!does_file_exist(g_mountlist_fname)) {
2892        mr_msg(2,
2893                "%ld: Warning - g_mountlist_fname (%s) does not exist yet",
2894                __LINE__, g_mountlist_fname);
2895    } else if (!does_file_exist(tmp)) {
2896        mr_free(tmp);
2897        mr_asprintf(&tmp, "cp -f %s %s.orig", g_mountlist_fname,
2898                g_mountlist_fname);
2899        run_program_and_log_output(tmp, FALSE);
2900    }
2901    mr_free(tmp);
2902
2903    /* Init directories */
2904    make_hole_for_dir("/var/log");
2905    make_hole_for_dir("/tmp/tmpfs");    /* just in case... */
2906    run_program_and_log_output("umount " MNT_CDROM, FALSE);
2907
2908    run_program_and_log_output("rm -Rf /tmp/tmpfs/mondo.tmp.*", FALSE);
2909
2910    /* Init GUI */
2911    malloc_libmondo_global_strings();
2912    setup_newt_stuff();         /* call newtInit and setup screen log */
2913    welcome_to_mondorestore();
2914    if (bkpinfo->disaster_recovery) {
2915        mr_msg(1, "I am in disaster recovery mode");
2916    } else {
2917        mr_msg(1, "I am in normal, live mode");
2918    }
2919
2920    iamhere("what time is it");
2921
2922    /* Process command-line parameters */
2923    if (argc == 2 && strcmp(argv[1], "--edit-mountlist") == 0) {
2924#ifdef __FreeBSD__
2925        system("mv -f /tmp/raidconf.txt /etc/raidtab");
2926        if (!does_file_exist("/etc/raidtab"))
2927            system("vinum printconfig > /etc/raidtab");
2928#endif
2929        load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
2930        if (!does_file_exist(g_mountlist_fname)) {
2931            strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
2932        }
2933        res = let_user_edit_the_mountlist(mountlist, raidlist);
2934#ifdef __FreeBSD__
2935        system("mv -f /etc/raidtab /tmp/raidconf.txt");
2936#endif
2937        paranoid_MR_finish(res);
2938    }
2939
2940    mr_conf->log_level = DEFAULT_MR_LOGLEVEL;
2941    if (argc == 3 && strcmp(argv[1], "--echo-to-screen") == 0) {
2942        fout = fopen("/tmp/out.txt", "w");
2943        fput_string_one_char_at_a_time(stderr, argv[2]);
2944        finish(0);
2945    }
2946
2947    if (argc == 3 && strcmp(argv[1], "--gendf") == 0) {
2948        make_grub_install_scriptlet(argv[2]);
2949        finish(0);
2950    }
2951
2952    if (argc == 5 && strcmp(argv[1], "--common") == 0) {
2953        mr_conf->log_level = 6;
2954        filelist = load_filelist(argv[2]);
2955        if (!filelist) {
2956            fatal_error("Failed to load filelist");
2957        }
2958        toggle_node_selection(filelist, FALSE);
2959        toggle_all_root_dirs_on(filelist);
2960        // BERLIOS: /usr/lib ???
2961        toggle_path_selection(filelist, "/usr/share", TRUE);
2962        save_filelist(filelist, "/tmp/out.txt");
2963        mr_asprintf(&a, argv[3]);
2964        mr_asprintf(&b, argv[4]);
2965
2966        res = save_filelist_entries_in_common(a, filelist, b, FALSE);
2967        free_filelist(filelist);
2968        mr_free(a);
2969        mr_free(b);
2970        printf("res = %d", res);
2971        finish(0);
2972    }
2973
2974    if (argc == 3 && strcmp(argv[1], "--popuplist") == 0) {
2975        popup_changelist_from_file(argv[2]);
2976        paranoid_MR_finish(0);
2977    }
2978
2979    if (argc == 5 && strcmp(argv[1], "--copy") == 0) {
2980        mr_msg(1, "SCORE");
2981        mr_conf->log_level = 10;
2982        if (strstr(argv[2], "save")) {
2983            mr_msg(1, "Saving from %s to %s", argv[3], argv[4]);
2984            fin = fopen(argv[3], "r");
2985            fout = fopen(argv[4], "w");
2986            copy_from_src_to_dest(fin, fout, 'w');
2987            fclose(fin);
2988            fin = fopen(argv[3], "r");
2989            copy_from_src_to_dest(fin, fout, 'w');
2990            fclose(fout);
2991            fclose(fin);
2992        } else if (strstr(argv[2], "restore")) {
2993            fout = fopen(argv[3], "w");
2994            fin = fopen(argv[4], "r");
2995            copy_from_src_to_dest(fout, fin, 'r');
2996            fclose(fin);
2997            fin = fopen(argv[4], "r");
2998            copy_from_src_to_dest(fout, fin, 'r');
2999            fclose(fout);
3000            fclose(fin);
3001        } else {
3002            fatal_error("Unknown additional param");
3003        }
3004        finish(0);
3005    }
3006
3007    if (argc == 2 && strcmp(argv[1], "--mdstat") == 0) {
3008        wait_until_software_raids_are_prepped(100);
3009        finish(0);
3010    }
3011
3012    if (argc == 3 && strcmp(argv[1], "--mdconv") == 0) {
3013        finish(create_raidtab_from_mdstat(argv[2]));
3014    }
3015
3016    if (argc == 3 && strcmp(argv[1], "-p") == 0) {
3017        mr_allocstr(bkpinfo->prefix,argv[2]);
3018        mr_msg(1,"Prefix forced to %s",bkpinfo->prefix);
3019    }
3020
3021    if (argc == 3 && strcmp(argv[1], "-K") == 0) {
3022        g_loglevel = atoi(argv[2]);
3023        log_msg(1,"Loglevel forced to %s",g_loglevel);
3024    }
3025
3026    if (argc == 2 && strcmp(argv[1], "--live-grub") == 0) {
3027        retval = run_grub(FALSE, "/dev/hda");
3028        if (retval) {
3029            log_to_screen(_("Failed to write Master Boot Record"));
3030        }
3031        paranoid_MR_finish(0);
3032    }
3033    if (argc == 3 && strcmp(argv[1], "--paa") == 0) {
3034        g_current_media_number = atoi(argv[2]);
3035        pause_and_ask_for_cdr(5);
3036        paranoid_MR_finish(0);
3037    } else if (!bkpinfo->disaster_recovery) {   // live!
3038        if (argc != 1) {
3039            popup_and_OK
3040                (_("Live mode doesn't support command-line parameters yet."));
3041            paranoid_MR_finish(1);
3042        }
3043        mr_msg(1, "I am in normal, live mode.");
3044        mr_msg(2, "FYI, MOUNTLIST_FNAME = %s", g_mountlist_fname);
3045        mount_boot_if_necessary();  /* for Gentoo users */
3046        mr_msg(2, "Still here.");
3047        if (argc > 1 && strcmp(argv[argc - 1], "--live-from-cd") == 0) {
3048            g_restoring_live_from_cd = TRUE;
3049        }
3050        if (bkpinfo->backup_media_type == nfs) {
3051            g_restoring_live_from_nfs = TRUE;
3052        }
3053        if (argc == 5 && strcmp(argv[1], "--monitas-live") == 0) {
3054            retval =
3055                restore_live_from_monitas_server(argv[2],
3056                                                 argv[3], argv[4]);
3057        } else {
3058            mr_msg(2, "Calling restore_to_live_filesystem()");
3059            retval = restore_to_live_filesystem();
3060        }
3061        mr_msg(2, "Still here. Yay.");
3062        if (strlen(bkpinfo->tmpdir) > 0) {
3063            mr_asprintf(&tmp, "rm -Rf %s/*", bkpinfo->tmpdir);
3064            run_program_and_log_output(tmp, FALSE);
3065            mr_free(tmp);
3066        }
3067        unmount_boot_if_necessary();    /* for Gentoo users */
3068        paranoid_MR_finish(retval);
3069    } else {
3070        /* Disaster recovery mode (must be) */
3071        mr_msg(1, "I must be in disaster recovery mode.");
3072        mr_msg(2, "FYI, MOUNTLIST_FNAME = %s ", g_mountlist_fname);
3073        if (argc == 3 && strcmp(argv[1], "--monitas-memorex") == 0) {
3074            log_to_screen(_("Uh, that hasn't been implemented yet."));
3075            paranoid_MR_finish(1);
3076        }
3077
3078        iamhere("About to call load_mountlist and load_raidtab");
3079        strcpy(bkpinfo->restore_path, MNT_RESTORING);
3080        read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
3081        retval = load_mountlist(mountlist, g_mountlist_fname);
3082        retval += load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
3083        iamhere
3084            ("Returned from calling load_mountlist and load_raidtab successfully");
3085
3086        if (argc > 1
3087            && (strcmp(argv[1], "--compare") == 0
3088                || strcmp(argv[1], "--nuke") == 0)) {
3089            if (bkpinfo->backup_media_type == nfs
3090                && !is_this_device_mounted(bkpinfo->nfs_mount)) {
3091                mr_msg(1, "Mounting nfs dir");
3092                sprintf(bkpinfo->isodir, "/tmp/isodir");
3093                run_program_and_log_output("mkdir -p /tmp/isodir", 5);
3094                mr_asprintf(&tmp, "mount %s -t nfs -o nolock /tmp/isodir",
3095                        bkpinfo->nfs_mount);
3096                run_program_and_log_output(tmp, 1);
3097                mr_free(tmp);
3098            }
3099        }
3100
3101
3102        if (retval) {
3103            log_to_screen
3104                (_("Warning - load_raidtab_into_raidlist returned an error"));
3105        }
3106
3107
3108        mr_msg(1, "Send in the clowns.");
3109
3110        if (argc == 2 && strcmp(argv[1], "--partition-only") == 0) {
3111            mr_msg(0, "Partitioning only.");
3112            load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
3113            strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
3114            load_mountlist(mountlist, g_mountlist_fname);
3115            res = partition_everything(mountlist);
3116            finish(res);
3117        }
3118
3119        if (argc == 2 && strcmp(argv[1], "--format-only") == 0) {
3120            mr_msg(0, "Formatting only.");
3121            load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
3122            strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
3123            load_mountlist(mountlist, g_mountlist_fname);
3124            res = format_everything(mountlist, FALSE, raidlist);
3125            finish(res);
3126        }
3127
3128        if (argc == 2 && strcmp(argv[1], "--stop-lvm-and-raid") == 0) {
3129            mr_msg(0, "Stopping LVM and RAID");
3130            load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
3131            strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
3132            load_mountlist(mountlist, g_mountlist_fname);
3133            res = do_my_funky_lvm_stuff(TRUE, FALSE);
3134            res += stop_all_raid_devices(mountlist);
3135            finish(res);
3136        }
3137
3138        if (argc == 2 && strcmp(argv[1], "--nuke") == 0) {
3139            iamhere("nuking");
3140            retval += nuke_mode(mountlist, raidlist);
3141        } else if (argc == 2 && strcmp(argv[1], "--interactive") == 0) {
3142            iamhere("catchall");
3143            retval += catchall_mode(mountlist, raidlist);
3144        } else if (argc == 2 && strcmp(argv[1], "--compare") == 0) {
3145            iamhere("compare");
3146            retval += compare_mode(mountlist, raidlist);
3147        } else if (argc == 2 && strcmp(argv[1], "--iso") == 0) {
3148            iamhere("iso");
3149            retval = iso_mode(mountlist, raidlist, FALSE);
3150        } else if (argc == 2 && strcmp(argv[1], "--mbr") == 0) {
3151            iamhere("mbr");
3152            retval = mount_all_devices(mountlist, TRUE);
3153            if (!retval) {
3154                retval += run_boot_loader(FALSE);
3155                retval += unmount_all_devices(mountlist);
3156            }
3157            if (retval) {
3158                log_to_screen(_("Failed to write Master Boot Record"));
3159            }
3160        } else if (argc == 2 && strcmp(argv[1], "--isonuke") == 0) {
3161            iamhere("isonuke");
3162            retval = iso_mode(mountlist, raidlist, TRUE);
3163        } else if (argc != 1) {
3164            log_to_screen(_("Invalid parameters"));
3165            paranoid_MR_finish(1);
3166        } else {
3167            iamhere("catchall (no mode specified in command-line call");
3168            retval += catchall_mode(mountlist, raidlist);
3169        }
3170    }
3171
3172    /* clean up at the end */
3173    if (retval) {
3174        if (does_file_exist(MONDO_CACHE"/changed.files")) {
3175            log_to_screen
3176                (_("See "MONDO_CACHE"/changed.files for list of files that have changed."));
3177        }
3178        mvaddstr_and_log_it(g_currentY++,
3179                            0,
3180                            _("Run complete. Errors were reported. Please review the logfile."));
3181    } else {
3182        if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3183            mvaddstr_and_log_it(g_currentY++,
3184                                0,
3185                                _("Run complete. Please remove media and reboot."));
3186        } else {
3187            run_program_and_log_output("sync", FALSE);
3188            if (is_this_device_mounted(MNT_CDROM)) {
3189                res =
3190                    run_program_and_log_output("umount " MNT_CDROM, FALSE);
3191            } else {
3192                res = 0;
3193            }
3194
3195            if (!bkpinfo->please_dont_eject) {
3196                res = eject_device("/dev/cdrom");
3197            }
3198            mvaddstr_and_log_it(g_currentY++,
3199                                0,
3200                                _("Run complete. Please remove media and reboot."));
3201        }
3202    }
3203
3204    // g_I_have_just_nuked is set true by nuke_mode() just before it returns
3205    if (!system("which post-nuke > /dev/null 2> /dev/null")) {
3206      mr_msg(1, "post-nuke found; find out whether we should run it...");
3207      if (g_I_have_just_nuked || does_file_exist("/POST-NUKE-ANYWAY")) {
3208        run_postnuke = TRUE;
3209        mr_msg(1, "Yes, will run post-nuke because in nuke mode or file /POST-NUKE-ANYWAY exists.");
3210      } else if (ask_me_yes_or_no("post-nuke script found. Do you want to run it?")) {
3211        run_postnuke = TRUE;
3212        mr_msg(1, "Yes, will run post-nuke because user interactively asked for it.");
3213      } else {
3214        run_postnuke = FALSE;
3215        mr_msg(1, "No, will not run post-nuke.");
3216      }
3217    } else {
3218      mr_msg(1, "No post-nuke found.");
3219    }
3220    if (run_postnuke) {
3221      log_to_screen("Running post-nuke...");
3222      if (mount_all_devices(mountlist, TRUE)) {
3223        log_to_screen
3224          ("Unable to re-mount partitions for post-nuke stuff");
3225      } else {
3226        mr_msg(1, "Re-mounted partitions for post-nuke stuff");
3227        mr_asprintf(&tmp, "post-nuke %s %d", bkpinfo->restore_path,
3228            retval);
3229        mr_msg(2, "Calling '%s'", tmp);
3230        if ((res = run_program_and_log_output(tmp, 0))) {
3231          log_OS_error(tmp);
3232        }
3233        mr_free(tmp);
3234        mr_msg(1, "post-nuke returned w/ res=%d", res);
3235      }
3236      unmount_all_devices(mountlist);
3237      log_to_screen("I've finished post-nuking.");
3238    }
3239
3240    unlink("/tmp/mondo-run-prog.tmp");
3241    set_signals(FALSE);
3242
3243    log_to_screen
3244        (_("Restore log (%s) copied to /var/log on your hard disk"), MONDO_LOGFILE);
3245    log_to_screen(_("Mondo-restore is exiting (retval=%d)"), retval);
3246
3247    mr_asprintf(&tmp, "umount %s", bkpinfo->isodir);
3248    run_program_and_log_output(tmp, 5);
3249    mr_free(tmp);
3250
3251    mr_free(mountlist);
3252    mr_free(raidlist);
3253    if (am_I_in_disaster_recovery_mode()) {
3254        run_program_and_log_output("mount / -o remount,rw", 2);
3255    }                           // for b0rken distros
3256    mr_asprintf(&tmp, "rm -Rf %s", bkpinfo->tmpdir);
3257    run_program_and_log_output(tmp, FALSE);
3258    mr_free(tmp);
3259
3260    paranoid_MR_finish(retval); // frees global stuff plus bkpinfo
3261    free_libmondo_global_strings(); // it's fine to have this here :) really :)
3262
3263    unlink("/tmp/filelist.full");
3264    unlink("/tmp/filelist.full.gz");
3265
3266    mr_exit(retval, NULL);
3267}
3268
3269/**************************************************************************
3270 *END_MAIN                                                                *
3271 **************************************************************************/
3272
3273
3274/**************************************************************************
3275 *END_MONDO-RESTORE.C                                                     *
3276 **************************************************************************/
3277=======
3278/***************************************************************************
3279$Id: mondorestore.c 1977 2008-06-02 08:49:01Z bruno $
3280restores mondoarchive data
3281***************************************************************************/
3282
3283/**
3284 * @file
3285 * The main file for mondorestore.
3286 */
3287
3288/**************************************************************************
3289 * #include statements                                                    *
3290 **************************************************************************/
3291#include <pthread.h>
3292#include "my-stuff.h"
3293#include "../common/mondostructures.h"
3294#include "../common/libmondo.h"
3295#include "mr-externs.h"
3296#include "mondo-restore.h"
3297#include "mondorestore.h"
3298#include "mondo-rstr-compare-EXT.h"
3299#include "mondo-rstr-tools-EXT.h"
3300
3301extern void twenty_seconds_til_yikes(void);
3302
3303/* Reference to global bkpinfo */
3304struct s_bkpinfo *bkpinfo;
3305
3306
3307/* For use in other programs (ex. XMondo) */
3308#ifdef MONDORESTORE_MODULE
3309#define main __mondorestore_main
3310#define g_ISO_restore_mode __mondorestore_g_ISO_restore_mode
3311#endif
3312
3313//static char cvsid[] = "$Id: mondorestore.c 1977 2008-06-02 08:49:01Z bruno $";
3314
3315/**************************************************************************
3316 * Globals                                                                *
3317 **************************************************************************/
3318extern char *g_tmpfs_mountpt;   // declared in libmondo-tools.c
3319extern bool g_text_mode;
3320extern FILE *g_fprep;
3321extern double g_kernel_version;
3322extern int g_partition_table_locked_up;
3323extern int g_noof_rows;
3324
3325extern int partition_everything(struct mountlist_itself *mountlist);
3326extern int handle_incoming_parameters(int argc, char *argv[]);
3327
3328/**
3329 * @name Restore-Time Globals
3330 * @ingroup globalGroup
3331 * @{
3332 */
3333
3334/**
3335 * If TRUE, then we're restoring from ISOs or an NFS server.
3336 * If FALSE, then we're restoring from some kind of real media (tape, CD, etc.)
3337 */
3338bool g_ISO_restore_mode = FALSE;    /* are we in Iso Mode? */
3339
3340/**
3341 * If TRUE, then we have had a successful "nuke" restore.
3342 */
3343bool g_I_have_just_nuked = FALSE;
3344
3345/**
3346 * The device to mount to get at the ISO images. Ignored unless @p g_ISO_restore_mode.
3347 */
3348char *g_isodir_device;
3349
3350/**
3351 * The format of @p g_isodir_device. Ignored unless @p g_ISO_restore_mode.
3352 */
3353char *g_isodir_format;
3354
3355/**
3356 * The location of 'biggielist.txt', containing the biggiefiles on the current archive set.
3357 */
3358char *g_biggielist_txt;
3359
3360/**
3361 * The location of 'filelist.full', containing all files (<em>including biggiefiles</em>) on
3362 * the current archive set.
3363 */
3364char *g_filelist_full;
3365
3366/**
3367 * The location of a file containing a list of the devices that were archived
3368 * as images, not as individual files.
3369 */
3370char *g_filelist_imagedevs;
3371
3372/**
3373 * The location of a file containing a list of imagedevs to actually restore.
3374 * @see g_filelist_imagedevs
3375 */
3376char *g_imagedevs_restthese;
3377
3378/**
3379 * The location of 'mondo-restore.cfg', containing the metadata
3380 * information for this backup.
3381 */
3382char *g_mondo_cfg_file;
3383
3384/**
3385 * The location of 'mountlist.txt', containing the information on the
3386 * user's partitions and hard drives.
3387 */
3388char *g_mountlist_fname;
3389
3390/**
3391 * Mondo's home directory during backup. Unused in mondorestore; included
3392 * to avoid link errors.
3393 */
3394char *g_mondo_home;
3395
3396extern char *g_getfacl;
3397extern char *g_getfattr;
3398
3399/* @} - end of "Restore-Time Globals" in globalGroup */
3400
3401
3402
3403extern int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived,
3404                                 char direction);
3405
3406
3407
3408/**************************************************************************
3409 * COMPAQ PROLIANT Stuff:  needs some special help                        *
3410**************************************************************************/
3411
3412/**
3413 * The message to display if we detect that the user is using a Compaq Proliant.
3414 */
3415#define COMPAQ_PROLIANTS_SUCK "Partition and format your disk using Compaq's disaster recovery CD. After you've done that, please reboot with your Mondo media in Interactive Mode."
3416
3417
3418
3419
3420/**
3421 * Allow the user to modify the mountlist before we partition & format their drives.
3422 * @param bkpinfo The backup information structure. @c disaster_recovery is the only field used.
3423 * @param mountlist The mountlist to let the user modify.
3424 * @param raidlist The raidlist that goes with @p mountlist.
3425 * @return 0 for success, nonzero for failure.
3426 * @ingroup restoreGuiGroup
3427 */
3428int let_user_edit_the_mountlist(struct mountlist_itself *mountlist,
3429                                struct raidlist_itself *raidlist)
3430{
3431    int retval = 0, res = 0;
3432
3433    log_msg(2, "let_user_edit_the_mountlist() --- starting");
3434
3435    assert(bkpinfo != NULL);
3436    assert(mountlist != NULL);
3437    assert(raidlist != NULL);
3438    if (!bkpinfo->disaster_recovery) {
3439        strcpy(g_mountlist_fname, "/tmp/mountlist.txt");
3440        log_msg(2, "I guess you're testing edit_mountlist()");
3441    }
3442    if (!does_file_exist(g_mountlist_fname)) {
3443        log_to_screen(g_mountlist_fname);
3444        log_to_screen("does not exist");
3445        return (1);
3446    }
3447
3448    retval = load_mountlist(mountlist, g_mountlist_fname);
3449    load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
3450    if (retval) {
3451        log_to_screen
3452            ("Warning - load_raidtab_into_raidlist returned an error");
3453    }
3454    res = edit_mountlist(g_mountlist_fname, mountlist, raidlist);
3455    if (res) {
3456        return (1);
3457    }
3458
3459    save_mountlist_to_disk(mountlist, g_mountlist_fname);
3460    save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME);
3461
3462    log_to_screen("I have finished editing the mountlist for you.");
3463
3464    return (retval);
3465}
3466
3467
3468
3469
3470
3471/**
3472 * Determine whether @p mountlist contains a Compaq diagnostic partition.
3473 * @param mountlist The mountlist to examine.
3474 * @return TRUE if there's a Compaq diagnostic partition; FALSE if not.
3475 * @ingroup restoreUtilityGroup
3476 */
3477bool
3478partition_table_contains_Compaq_diagnostic_partition(struct
3479                                                     mountlist_itself *
3480                                                     mountlist)
3481{
3482    int i;
3483
3484    assert(mountlist != NULL);
3485
3486    for (i = 0; i < mountlist->entries; i++) {
3487        if (strstr(mountlist->el[i].format, "ompaq")) {
3488            log_msg(2, "mountlist[%d] (%s) is %s (Compaq alert!)",
3489                    i, mountlist->el[i].device, mountlist->el[i].format);
3490
3491            return (TRUE);
3492        }
3493    }
3494    return (FALSE);
3495}
3496
3497/**************************************************************************
3498 *END_PARTITION_TABLE_CONTAINS_COMPAQ_DIAGNOSTIC_PARTITION                *
3499 **************************************************************************/
3500
3501
3502/**
3503 * Allow the user to abort the backup if we find that there is a Compaq diagnostic partition.
3504 * @note This function does not actually check for the presence of a Compaq partition.
3505 * @ingroup restoreUtilityGroup
3506 */
3507void offer_to_abort_because_Compaq_Proliants_suck(void)
3508{
3509    popup_and_OK(COMPAQ_PROLIANTS_SUCK);
3510    if (ask_me_yes_or_no
3511        ("Would you like to reboot and use your Compaq CD to prep your hard drive?"))
3512    {
3513        fatal_error
3514            ("Aborting. Please reboot and prep your hard drive with your Compaq CD.");
3515    }
3516}
3517
3518/**************************************************************************
3519 *END_OFFER_TO_ABORT_BECAUSE_COMPAQ_PROLIANTS_SUCK                        *
3520 **************************************************************************/
3521
3522
3523
3524/**
3525 * Call interactive_mode(), nuke_mode(), or compare_mode() depending on the user's choice.
3526 * @param bkpinfo The backup information structure. Most fields are used.
3527 * @param mountlist The mountlist containing information about the user's partitions.
3528 * @param raidlist The raidlist to go with @p mountlist.
3529 * @return The return code from the mode function called.
3530 * @ingroup restoreGroup
3531 */
3532int
3533catchall_mode(struct mountlist_itself *mountlist,
3534              struct raidlist_itself *raidlist)
3535{
3536    char c, *tmp;
3537    int retval = 0;
3538
3539    iamhere("inside catchall");
3540    assert(bkpinfo != NULL);
3541    assert(mountlist != NULL);
3542    assert(raidlist != NULL);
3543    malloc_string(tmp);
3544    iamhere("pre wrm");
3545    c = which_restore_mode();
3546    iamhere("post wrm");
3547    if (c == 'I' || c == 'C') {
3548        interactively_obtain_media_parameters_from_user(FALSE);
3549    } else if (c == 'N') {
3550        // Auto mode nothing special to do
3551    } else {
3552        popup_and_OK("No restoring or comparing will take place today.");
3553        if (is_this_device_mounted("/mnt/cdrom")) {
3554            run_program_and_log_output("umount /mnt/cdrom", FALSE);
3555        }
3556        if (g_ISO_restore_mode) {
3557            sprintf(tmp, "umount %s", bkpinfo->isodir);
3558            run_program_and_log_output(tmp, FALSE);
3559        }
3560        paranoid_MR_finish(0);
3561    }
3562
3563    iamhere("post int");
3564
3565    if (bkpinfo->backup_media_type == iso) {
3566        if (iso_fiddly_bits((c == 'N') ? TRUE : FALSE)) {
3567            log_msg(2,
3568                    "catchall_mode --- iso_fiddly_bits returned w/ error");
3569            return (1);
3570        } else {
3571            log_msg(2, "catchall_mode --- iso_fiddly_bits ok");
3572        }
3573    }
3574
3575    if (c == 'I') {
3576        log_msg(2, "IM selected");
3577        retval += interactive_mode(mountlist, raidlist);
3578    } else if (c == 'N') {
3579        log_msg(2, "NM selected");
3580        retval += nuke_mode(mountlist, raidlist);
3581    } else if (c == 'C') {
3582        log_msg(2, "CM selected");
3583        retval += compare_mode(mountlist, raidlist);
3584    }
3585    paranoid_free(tmp);
3586    return (retval);
3587}
3588
3589/**************************************************************************
3590 *END_CATCHALL_MODE                                                      *
3591 **************************************************************************/
3592
3593/**************************************************************************
3594 *END_  EXTRACT_CONFIG_FILE_FROM_RAMDISK                                  *
3595 **************************************************************************/
3596
3597
3598/**
3599 * Locate an executable in the directory structure rooted at @p restg.
3600 * @param out_path Where to put the executable.
3601 * @param fname The basename of the executable.
3602 * @param restg The directory structure to look in.
3603 * @note If it could not be found in @p restg then @p fname is put in @p out_path.
3604 * @ingroup restoreUtilityGroup
3605 */
3606void
3607find_pathname_of_executable_preferably_in_RESTORING(char *out_path,
3608                                                    char *fname,
3609                                                    char *restg)
3610{
3611    assert(out_path != NULL);
3612    assert_string_is_neither_NULL_nor_zerolength(fname);
3613
3614    sprintf(out_path, "%s/sbin/%s", restg, fname);
3615    if (does_file_exist(out_path)) {
3616        sprintf(out_path, "%s/usr/sbin/%s", restg, fname);
3617        if (does_file_exist(out_path)) {
3618            sprintf(out_path, "%s/bin/%s", restg, fname);
3619            if (does_file_exist(out_path)) {
3620                sprintf(out_path, "%s/usr/bin/%s", restg, fname);
3621                if (does_file_exist(out_path)) {
3622                    strcpy(out_path, fname);
3623                }
3624            }
3625        }
3626    }
3627}
3628
3629/**************************************************************************
3630 *END_FIND_PATHNAME_OF_EXECUTABLE_PREFERABLY_IN_RESTORING                 *
3631 **************************************************************************/
3632
3633static void clean_blkid() {
3634
3635    char *tmp1 = NULL;
3636
3637    /* Clean up blkid cache file if they exist */
3638    asprintf(&tmp1,"%s/etc/blkid.tab",bkpinfo->restore_path);
3639    (void)unlink(tmp1);
3640    paranoid_free(tmp1);
3641    asprintf(&tmp1,"%s/etc/blkid.tab.old",bkpinfo->restore_path);
3642    (void)unlink(tmp1);
3643    paranoid_free(tmp1);
3644}
3645
3646
3647
3648
3649/**
3650 * @addtogroup restoreGroup
3651 * @{
3652 */
3653/**
3654 * Restore the user's data, in a disaster recovery situation, prompting the
3655 * user about whether or not to do every step.
3656 * The user can edit the mountlist, choose files to restore, etc.
3657 * @param bkpinfo The backup information structure. Most fields are used.
3658 * @param mountlist The mountlist containing information about the user's partitions.
3659 * @param raidlist The raidlist to go with @p mountlist.
3660 * @return 0 for success, or the number of errors encountered.
3661 */
3662int
3663interactive_mode(struct mountlist_itself *mountlist,
3664                 struct raidlist_itself *raidlist)
3665{
3666    int retval = 0;
3667    int res;
3668    int ptn_errs = 0;
3669    int fmt_errs = 0;
3670
3671    bool done;
3672    bool restore_all;
3673
3674  /** needs malloc **********/
3675    char *tmp;
3676    char *fstab_fname;
3677    char *old_restpath;
3678
3679    struct s_node *filelist;
3680
3681    /* try to partition and format */
3682
3683    log_msg(2, "interactive_mode --- starting (great, assertions OK)");
3684
3685    malloc_string(tmp);
3686    malloc_string(fstab_fname);
3687    malloc_string(old_restpath);
3688    assert(bkpinfo != NULL);
3689    assert(mountlist != NULL);
3690    assert(raidlist != NULL);
3691
3692    log_msg(2, "interactive_mode --- assertions OK");
3693
3694    if (g_text_mode) {
3695        if (!ask_me_yes_or_no
3696            ("Interactive Mode + textonly = experimental! Proceed anyway?"))
3697        {
3698            fatal_error("Wise move.");
3699        }
3700    }
3701
3702    iamhere("About to load config file");
3703    get_cfg_file_from_archive_or_bust();
3704    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
3705    iamhere("Done loading config file; resizing ML");
3706    if (bkpinfo->backup_media_type == nfs) {
3707        strcpy(tmp, bkpinfo->prefix);
3708        if (popup_and_get_string
3709            ("Prefix", "Prefix of your ISO images ?", tmp, MAX_STR_LEN / 4)) {
3710            strcpy(bkpinfo->prefix, tmp);
3711            log_msg(1, "Prefix set to %s",bkpinfo->prefix);
3712        }
3713    }
3714
3715#ifdef __FreeBSD__
3716    if (strstr
3717        (call_program_and_get_last_line_of_output("cat /tmp/cmdline"),
3718         "noresize"))
3719#else
3720    if (strstr
3721        (call_program_and_get_last_line_of_output("cat /proc/cmdline"),
3722         "noresize"))
3723#endif
3724    {
3725        log_msg(1, "Not resizing mountlist.");
3726    } else {
3727        resize_mountlist_proportionately_to_suit_new_drives(mountlist);
3728    }
3729    for (done = FALSE; !done;) {
3730        iamhere("About to edit mountlist");
3731        if (g_text_mode) {
3732            save_mountlist_to_disk(mountlist, g_mountlist_fname);
3733            sprintf(tmp, "%s %s", find_my_editor(), g_mountlist_fname);
3734            res = system(tmp);
3735            load_mountlist(mountlist, g_mountlist_fname);
3736        } else {
3737            res = edit_mountlist(g_mountlist_fname, mountlist, raidlist);
3738        }
3739        iamhere("Finished editing mountlist");
3740        if (res) {
3741            paranoid_MR_finish(1);
3742        }
3743        log_msg(2, "Proceeding...");
3744        save_mountlist_to_disk(mountlist, g_mountlist_fname);
3745        save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME);
3746        mvaddstr_and_log_it(1, 30, "Restoring Interactively");
3747        if (bkpinfo->differential) {
3748            log_to_screen("Because this is a differential backup, disk");
3749            log_to_screen
3750                (" partitioning and formatting will not take place.");
3751            done = TRUE;
3752        } else {
3753            if (ask_me_yes_or_no
3754                ("Do you want to erase and partition your hard drives?")) {
3755                if (partition_table_contains_Compaq_diagnostic_partition
3756                    (mountlist)) {
3757                    offer_to_abort_because_Compaq_Proliants_suck();
3758                    done = TRUE;
3759                } else {
3760                    twenty_seconds_til_yikes();
3761                    g_fprep = fopen("/tmp/prep.sh", "w");
3762                    ptn_errs = partition_everything(mountlist);
3763                    if (ptn_errs) {
3764                        log_to_screen
3765                            ("Warning. Errors occurred during disk partitioning.");
3766                    }
3767
3768                    fmt_errs = format_everything(mountlist, FALSE, raidlist);
3769                    if (!fmt_errs) {
3770                        log_to_screen
3771                            ("Errors during disk partitioning were handled OK.");
3772                        log_to_screen
3773                            ("Partitions were formatted OK despite those errors.");
3774                        ptn_errs = 0;
3775                    }
3776                    if (!ptn_errs && !fmt_errs) {
3777                        done = TRUE;
3778                    }
3779                }
3780                paranoid_fclose(g_fprep);
3781            } else {
3782                mvaddstr_and_log_it(g_currentY++, 0,
3783                                    "User opted not to partition the devices");
3784                if (ask_me_yes_or_no
3785                    ("Do you want to format your hard drives?")) {
3786                    fmt_errs = format_everything(mountlist, TRUE, raidlist);
3787                    if (!fmt_errs) {
3788                        done = TRUE;
3789                    }
3790                } else {
3791                    ptn_errs = fmt_errs = 0;
3792                    done = TRUE;
3793                }
3794            }
3795            if (fmt_errs) {
3796                mvaddstr_and_log_it(g_currentY++,
3797                                    0,
3798                                    "Errors occurred. Please repartition and format drives manually.");
3799                done = FALSE;
3800            }
3801            if (ptn_errs & !fmt_errs) {
3802                mvaddstr_and_log_it(g_currentY++,
3803                                    0,
3804                                    "Errors occurred during partitioning. Formatting, however, went OK.");
3805                done = TRUE;
3806            }
3807            if (!done) {
3808                if (!ask_me_yes_or_no("Re-edit the mountlist?")) {
3809                    retval++;
3810                    goto end_of_func;
3811                }
3812            }
3813        }
3814    }
3815
3816    /* mount */
3817    if (mount_all_devices(mountlist, TRUE)) {
3818        unmount_all_devices(mountlist);
3819        retval++;
3820        goto end_of_func;
3821    }
3822    /* restore */
3823    if ((restore_all =
3824         ask_me_yes_or_no("Do you want me to restore all of your data?")))
3825    {
3826        log_msg(1, "Restoring all data");
3827        retval += restore_everything(NULL);
3828    } else
3829        if ((restore_all =
3830             ask_me_yes_or_no
3831             ("Do you want me to restore _some_ of your data?"))) {
3832        strcpy(old_restpath, bkpinfo->restore_path);
3833        for (done = FALSE; !done;) {
3834            unlink("/tmp/filelist.full");
3835            filelist = process_filelist_and_biggielist();
3836            /* Now you have /tmp/tmpfs/filelist.restore-these and /tmp/tmpfs/biggielist.restore-these;
3837               the former is a list of regular files; the latter, biggiefiles and imagedevs.
3838             */
3839            if (filelist) {
3840              gotos_suck:
3841                strcpy(tmp, old_restpath);
3842// (NB: %s is where your filesystem is mounted now, by default)", MNT_RESTORING);
3843                if (popup_and_get_string
3844                    ("Restore path", "Restore files to where?", tmp,
3845                     MAX_STR_LEN / 4)) {
3846                    if (!strcmp(tmp, "/")) {
3847                        if (!ask_me_yes_or_no("Are you sure?")) {
3848                            goto gotos_suck;
3849                        }
3850                        tmp[0] = '\0';  // so we restore to [blank]/file/name :)
3851                    }
3852                    strcpy(bkpinfo->restore_path, tmp);
3853                    log_msg(1, "Restoring subset");
3854                    retval += restore_everything(filelist);
3855                    free_filelist(filelist);
3856                } else {
3857                    strcpy(bkpinfo->restore_path, old_restpath);
3858                    free_filelist(filelist);
3859                }
3860                if (!ask_me_yes_or_no
3861                    ("Restore another subset of your backup?")) {
3862                    done = TRUE;
3863                }
3864            } else {
3865                done = TRUE;
3866            }
3867        }
3868        strcpy(old_restpath, bkpinfo->restore_path);
3869    } else {
3870        mvaddstr_and_log_it(g_currentY++,
3871                            0,
3872                            "User opted not to restore any data.                                  ");
3873    }
3874    if (retval) {
3875        mvaddstr_and_log_it(g_currentY++,
3876                            0,
3877                            "Errors occurred during the restore phase.            ");
3878    }
3879
3880    if (ask_me_yes_or_no("Initialize the boot loader?")) {
3881        run_boot_loader(TRUE);
3882    } else {
3883        mvaddstr_and_log_it(g_currentY++,
3884                            0,
3885                            "User opted not to initialize the boot loader.");
3886    }
3887
3888    clean_blkid();
3889    protect_against_braindead_sysadmins();
3890    retval += unmount_all_devices(mountlist);
3891    /*  if (restore_some || restore_all || */
3892    if (ask_me_yes_or_no
3893        ("Label/Identify your ext2 and ext3 partitions if necessary?")) {
3894        mvaddstr_and_log_it(g_currentY, 0,
3895                            "Using tune2fs to identify your ext2,3 partitions");
3896        if (does_file_exist("/tmp/fstab.new")) {
3897            strcpy(fstab_fname, "/tmp/fstab.new");
3898        } else {
3899            strcpy(fstab_fname, "/tmp/fstab");
3900        }
3901        sprintf(tmp,
3902                "label-partitions-as-necessary %s < %s >> %s 2>> %s",
3903                g_mountlist_fname, fstab_fname, MONDO_LOGFILE,
3904                MONDO_LOGFILE);
3905        res = system(tmp);
3906        if (res) {
3907            log_to_screen
3908                ("label-partitions-as-necessary returned an error");
3909            mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
3910        } else {
3911            mvaddstr_and_log_it(g_currentY++, 74, "Done.");
3912        }
3913        retval += res;
3914    }
3915
3916    iamhere("About to leave interactive_mode()");
3917    if (retval) {
3918        mvaddstr_and_log_it(g_currentY++,
3919                            0,
3920                            "Warning - errors occurred during the restore phase.");
3921    }
3922  end_of_func:
3923    paranoid_free(tmp);
3924    paranoid_free(fstab_fname);
3925    paranoid_free(old_restpath);
3926    iamhere("Leaving interactive_mode()");
3927    return (retval);
3928}
3929
3930/**************************************************************************
3931 *END_INTERACTIVE_MODE                                                    *
3932 **************************************************************************/
3933
3934
3935
3936/**
3937 * Run an arbitrary restore mode (prompt the user), but from ISO images
3938 * instead of real media.
3939 * @param mountlist The mountlist containing information about the user's partitions.
3940 * @param raidlist The raidlist that goes with @p mountlist.
3941 * @param nuke_me_please If TRUE, we plan to run Nuke Mode.
3942 * @return 0 for success, or the number of errors encountered.
3943 */
3944int
3945iso_mode(struct mountlist_itself *mountlist,
3946         struct raidlist_itself *raidlist, bool nuke_me_please)
3947{
3948    char c;
3949    int retval = 0;
3950
3951    assert(mountlist != NULL);
3952    assert(raidlist != NULL);
3953    if (iso_fiddly_bits(nuke_me_please)) {
3954        log_msg(1, "iso_mode --- returning w/ error");
3955        return (1);
3956    } else {
3957        c = which_restore_mode();
3958        if (c == 'I' || c == 'N' || c == 'C') {
3959            interactively_obtain_media_parameters_from_user(FALSE);
3960        }
3961        if (c == 'I') {
3962            retval += interactive_mode(mountlist, raidlist);
3963        } else if (c == 'N') {
3964            retval += nuke_mode(mountlist, raidlist);
3965        } else if (c == 'C') {
3966            retval += compare_mode(mountlist, raidlist);
3967        } else {
3968            log_to_screen("OK, I shan't restore/compare any files.");
3969        }
3970    }
3971    if (is_this_device_mounted(MNT_CDROM)) {
3972        paranoid_system("umount " MNT_CDROM);
3973    }
3974//  if (! already_mounted)
3975//    {
3976    if (system("umount /tmp/isodir 2> /dev/null")) {
3977        log_to_screen
3978            ("WARNING - unable to unmount device where the ISO files are stored.");
3979    }
3980//    }
3981    return (retval);
3982}
3983
3984/**************************************************************************
3985 *END_ISO_MODE                                                            *
3986 **************************************************************************/
3987
3988
3989/*            MONDO - saving your a$$ since Feb 18th, 2000            */
3990
3991
3992
3993
3994/**
3995 * Restore the user's data automatically (no prompts), after a twenty-second
3996 * warning period.
3997 * @param bkpinfo The backup information structure. Most fields are used.
3998 * @param mountlist The mountlist containing information about the user's partitions.
3999 * @param raidlist The raidlist that goes with @p mountlist.
4000 * @return 0 for success, or the number of errors encountered.
4001 * @warning <b><i>THIS WILL ERASE ALL EXISTING DATA!</i></b>
4002 */
4003int
4004nuke_mode(struct mountlist_itself *mountlist,
4005          struct raidlist_itself *raidlist)
4006{
4007    int retval = 0;
4008    int res = 0;
4009    bool boot_loader_installed = FALSE;
4010  /** malloc **/
4011    char tmp[MAX_STR_LEN], tmpA[MAX_STR_LEN], tmpB[MAX_STR_LEN],
4012        tmpC[MAX_STR_LEN];
4013
4014    assert(bkpinfo != NULL);
4015    assert(mountlist != NULL);
4016    assert(raidlist != NULL);
4017
4018    log_msg(2, "nuke_mode --- starting");
4019
4020    get_cfg_file_from_archive_or_bust();
4021    load_mountlist(mountlist, g_mountlist_fname);   // in case read_cfg_file_into_bkpinfo updated the mountlist
4022#ifdef __FreeBSD__
4023    if (strstr
4024        (call_program_and_get_last_line_of_output("cat /tmp/cmdline"),
4025         "noresize"))
4026#else
4027    if (strstr
4028        (call_program_and_get_last_line_of_output("cat /proc/cmdline"),
4029         "noresize"))
4030#endif
4031    {
4032        log_msg(2, "Not resizing mountlist.");
4033    } else {
4034        resize_mountlist_proportionately_to_suit_new_drives(mountlist);
4035    }
4036    if (!evaluate_mountlist(mountlist, tmpA, tmpB, tmpC)) {
4037        sprintf(tmp,
4038                "Mountlist analyzed. Result: \"%s %s %s\" Switch to Interactive Mode?",
4039                tmpA, tmpB, tmpC);
4040        if (ask_me_yes_or_no(tmp)) {
4041            retval = interactive_mode(mountlist, raidlist);
4042            goto after_the_nuke;
4043        } else {
4044            fatal_error("Nuke Mode aborted. ");
4045        }
4046    }
4047    save_mountlist_to_disk(mountlist, g_mountlist_fname);
4048    mvaddstr_and_log_it(1, 30, "Restoring Automatically");
4049    if (bkpinfo->differential) {
4050        log_to_screen("Because this is a differential backup, disk");
4051        log_to_screen("partitioning and formatting will not take place.");
4052        res = 0;
4053    } else {
4054        if (partition_table_contains_Compaq_diagnostic_partition
4055            (mountlist)) {
4056            offer_to_abort_because_Compaq_Proliants_suck();
4057        } else {
4058            twenty_seconds_til_yikes();
4059            g_fprep = fopen("/tmp/prep.sh", "w");
4060#ifdef __FreeBSD__
4061            if (strstr
4062                (call_program_and_get_last_line_of_output
4063                 ("cat /tmp/cmdline"), "nopart"))
4064#else
4065            if (strstr
4066                (call_program_and_get_last_line_of_output
4067                 ("cat /proc/cmdline"), "nopart"))
4068#endif
4069            {
4070                log_msg(2,
4071                        "Not partitioning drives due to 'nopart' option.");
4072                res = 0;
4073            } else {
4074                res = partition_everything(mountlist);
4075                if (res) {
4076                    log_to_screen
4077                        ("Warning. Errors occurred during partitioning.");
4078                    res = 0;
4079                }
4080            }
4081            retval += res;
4082            if (!res) {
4083                log_to_screen("Preparing to format your disk(s)");
4084                sleep(1);
4085                system("sync");
4086                log_to_screen("Please wait. This may take a few minutes.");
4087                res += format_everything(mountlist, FALSE, raidlist);
4088            }
4089            paranoid_fclose(g_fprep);
4090        }
4091    }
4092    retval += res;
4093    if (res) {
4094        mvaddstr_and_log_it(g_currentY++,
4095                            0,
4096                            "Failed to partition and/or format your hard drives.");
4097
4098        if (ask_me_yes_or_no("Try in interactive mode instead?")) {
4099            retval = interactive_mode(mountlist, raidlist);
4100            goto after_the_nuke;
4101        } else
4102            if (!ask_me_yes_or_no
4103                ("Would you like to try to proceed anyway?")) {
4104            return (retval);
4105        }
4106    }
4107    retval = mount_all_devices(mountlist, TRUE);
4108    if (retval) {
4109        unmount_all_devices(mountlist);
4110        log_to_screen
4111            ("Unable to mount all partitions. Sorry, I cannot proceed.");
4112        return (retval);
4113    }
4114    iamhere("Restoring everything");
4115    retval += restore_everything(NULL);
4116    if (!run_boot_loader(FALSE)) {
4117        log_msg(1,
4118                "Great! Boot loader was installed. No need for msg at end.");
4119        boot_loader_installed = TRUE;
4120    }
4121    clean_blkid();
4122    protect_against_braindead_sysadmins();
4123    retval += unmount_all_devices(mountlist);
4124    mvaddstr_and_log_it(g_currentY,
4125                        0,
4126                        "Using tune2fs to identify your ext2,3 partitions");
4127
4128    sprintf(tmp, "label-partitions-as-necessary %s < /tmp/fstab",
4129            g_mountlist_fname);
4130    res = run_program_and_log_output(tmp, TRUE);
4131    if (res) {
4132        log_to_screen("label-partitions-as-necessary returned an error");
4133        mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
4134    } else {
4135        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
4136    }
4137    retval += res;
4138
4139  after_the_nuke:
4140    if (retval) {
4141        log_to_screen("Errors occurred during the nuke phase.");
4142    } else if (strstr(call_program_and_get_last_line_of_output("cat /proc/cmdline"), "RESTORE")) {
4143        log_to_screen
4144            ("PC was restored successfully. Thank you for using Mondo Rescue.");
4145        log_to_screen
4146            ("Please visit our website at http://www.mondorescue.org for more information.");
4147    } else {
4148        strcpy(tmp,"Mondo has restored your system.\n\nPlease wait for the command prompt. Then remove the backup media and reboot.\n\nPlease visit our website at http://www.mondorescue.org for more information.");
4149            popup_and_OK(tmp);
4150        log_to_screen
4151          ("Mondo has restored your system. Please wait for the command prompt.");
4152        log_to_screen
4153            ("Then remove the backup media and reboot.");
4154        log_to_screen
4155            ("Please visit our website at http://www.mondorescue.org for more information.");
4156    }
4157    g_I_have_just_nuked = TRUE;
4158/*
4159  if (!boot_loader_installed && !does_file_exist(DO_MBR_PLEASE))
4160    {
4161      log_to_screen("PLEASE RUN 'mondorestore --mbr' NOW TO INITIALIZE YOUR BOOT SECTOR");
4162      write_one_liner_data_file(DO_MBR_PLEASE, "mondorestore --mbr");
4163    }
4164*/
4165    return (retval);
4166}
4167
4168/**************************************************************************
4169 *END_NUKE_MODE                                                           *
4170 **************************************************************************/
4171
4172
4173
4174/**
4175 * Restore the user's data (or a subset of it) to the live filesystem.
4176 * This should not be called if we're booted from CD!
4177 * @param bkpinfo The backup information structure. Most fields are used.
4178 * @return 0 for success, or the number of errors encountered.
4179 */
4180int restore_to_live_filesystem()
4181{
4182    int retval = 0;
4183
4184  /** malloc **/
4185    char *old_restpath;
4186
4187    struct mountlist_itself *mountlist;
4188//  static
4189    struct raidlist_itself *raidlist;
4190    struct s_node *filelist;
4191
4192    log_msg(1, "restore_to_live_filesystem() - starting");
4193    assert(bkpinfo != NULL);
4194    malloc_string(old_restpath);
4195    mountlist = malloc(sizeof(struct mountlist_itself));
4196    raidlist = malloc(sizeof(struct raidlist_itself));
4197    if (!mountlist || !raidlist) {
4198        fatal_error("Cannot malloc() mountlist and/or raidlist");
4199    }
4200
4201    strcpy(bkpinfo->restore_path, "/");
4202    if (!g_restoring_live_from_cd && !g_restoring_live_from_nfs) {
4203        popup_and_OK
4204            ("Please insert tape/CD/USB Key, then hit 'OK' to continue.");
4205        sleep(1);
4206    }
4207    if (!g_restoring_live_from_nfs) {
4208        interactively_obtain_media_parameters_from_user(FALSE);
4209    }
4210    log_msg(2, "bkpinfo->media_device = %s", bkpinfo->media_device);
4211    if (!bkpinfo->media_device[0]) {
4212        log_msg(2, "Warning - failed to find media dev");
4213    }
4214
4215
4216    log_msg(2, "bkpinfo->isodir = %s", bkpinfo->isodir);
4217
4218    open_evalcall_form("Thinking...");
4219
4220    get_cfg_file_from_archive_or_bust();
4221    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
4222    load_mountlist(mountlist, g_mountlist_fname);   // in case read_cfg_file_into_bkpinfo
4223
4224    close_evalcall_form();
4225    retval = load_mountlist(mountlist, g_mountlist_fname);
4226    load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
4227
4228    if (!g_restoring_live_from_nfs && (filelist = process_filelist_and_biggielist())) {
4229        save_filelist(filelist, "/tmp/selected-files.txt");
4230        strcpy(old_restpath, bkpinfo->restore_path);
4231        if (popup_and_get_string("Restore path",
4232                                 "Restore files to where? )",
4233                                 bkpinfo->restore_path, MAX_STR_LEN / 4)) {
4234            iamhere("Restoring everything");
4235            retval += restore_everything(filelist);
4236            free_filelist(filelist);
4237            strcpy(bkpinfo->restore_path, old_restpath);
4238        } else {
4239            free_filelist(filelist);
4240        }
4241        strcpy(bkpinfo->restore_path, old_restpath);
4242    } else {
4243        retval += restore_everything(NULL);
4244    }
4245    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
4246        log_msg(2,
4247                "Tape : I don't need to unmount or eject the CD-ROM.");
4248    } else {
4249        run_program_and_log_output("umount " MNT_CDROM, FALSE);
4250        if (!bkpinfo->please_dont_eject) {
4251            eject_device(bkpinfo->media_device);
4252        }
4253    }
4254    run_program_and_log_output("umount " MNT_CDROM, FALSE);
4255    if (!bkpinfo->please_dont_eject) {
4256        eject_device(bkpinfo->media_device);
4257    }
4258    paranoid_free(old_restpath);
4259    free(mountlist);
4260    free(raidlist);
4261    return (retval);
4262}
4263
4264/**************************************************************************
4265 *END_RESTORE_TO_LIVE_FILESYSTEM                                          *
4266 **************************************************************************/
4267
4268/* @} - end of restoreGroup */
4269
4270
4271#include <utime.h>
4272/**
4273 * @addtogroup LLrestoreGroup
4274 * @{
4275 */
4276/**
4277 * Restore biggiefile @p bigfileno from the currently mounted CD.
4278 * @param bkpinfo The backup information structure. Fields used:
4279 * - @c bkpinfo->backup_media_type
4280 * - @c bkpinfo->restore_path
4281 * @param bigfileno The biggiefile number (starting from 0) to restore.
4282 * @param filelist The node structure containing the list of files to restore.
4283 * If the biggiefile is not in this list, it will be skipped (return value will
4284 * still indicate success).
4285 * @return 0 for success (or skip), nonzero for failure.
4286 */
4287int
4288restore_a_biggiefile_from_CD(long bigfileno,
4289                             struct s_node *filelist,
4290                             char *pathname_of_last_file_restored)
4291{
4292    FILE *fin;
4293    FILE *fout;
4294    FILE *fbzip2;
4295
4296  /** malloc ***/
4297    char *checksum, *outfile_fname, *tmp, *bzip2_command,
4298        *ntfsprog_command, *suffix, *sz_devfile;
4299    char *bigblk;
4300    char *p;
4301    int retval = 0;
4302    int finished = FALSE;
4303    long sliceno;
4304    long siz;
4305    char ntfsprog_fifo[MAX_STR_LEN];
4306    char *file_to_openout = NULL;
4307    struct s_filename_and_lstat_info biggiestruct;
4308    struct utimbuf the_utime_buf, *ubuf;
4309    bool use_ntfsprog_hack = FALSE;
4310    pid_t pid;
4311    int res = 0;
4312    int old_loglevel;
4313    char sz_msg[MAX_STR_LEN];
4314    struct s_node *node;
4315
4316    old_loglevel = g_loglevel;
4317    ubuf = &the_utime_buf;
4318    assert(bkpinfo != NULL);
4319
4320    malloc_string(checksum);
4321    malloc_string(outfile_fname);
4322    malloc_string(tmp);
4323    malloc_string(bzip2_command);
4324    malloc_string(ntfsprog_command);
4325    malloc_string(suffix);
4326    malloc_string(sz_devfile);
4327
4328    pathname_of_last_file_restored[0] = '\0';
4329    if (!(bigblk = malloc(TAPE_BLOCK_SIZE))) {
4330        fatal_error("Cannot malloc bigblk");
4331    }
4332
4333    if (!(fin = fopen(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""), "r"))) {
4334        log_to_screen("Cannot even open bigfile's info file");
4335        return (1);
4336    }
4337
4338    memset((void *) &biggiestruct, 0, sizeof(biggiestruct));
4339    if (fread((void *) &biggiestruct, 1, sizeof(biggiestruct), fin) <
4340        sizeof(biggiestruct)) {
4341        log_msg(2, "Warning - unable to get biggiestruct of bigfile #%d",
4342                bigfileno + 1);
4343    }
4344    paranoid_fclose(fin);
4345
4346    strcpy(checksum, biggiestruct.checksum);
4347
4348    if (!checksum[0]) {
4349        sprintf(tmp, "Warning - bigfile %ld does not have a checksum",
4350                bigfileno + 1);
4351        log_msg(3, tmp);
4352        p = checksum;
4353    }
4354
4355    if (!strncmp(biggiestruct.filename, "/dev/", 5))    // Whether NTFS or not :)
4356    {
4357        strcpy(outfile_fname, biggiestruct.filename);
4358    } else {
4359        sprintf(outfile_fname, "%s/%s", bkpinfo->restore_path,
4360                biggiestruct.filename);
4361    }
4362
4363    /* skip file if we have a selective restore subset & it doesn't match */
4364    if (filelist != NULL) {
4365        node = find_string_at_node(filelist, biggiestruct.filename);
4366        if (!node) {
4367            log_msg(0, "Skipping %s (name isn't in filelist)",
4368                    biggiestruct.filename);
4369            pathname_of_last_file_restored[0] = '\0';
4370            return (0);
4371        } else if (!(node->selected)) {
4372            log_msg(1, "Skipping %s (name isn't in biggielist subset)",
4373                    biggiestruct.filename);
4374            pathname_of_last_file_restored[0] = '\0';
4375            return (0);
4376        }
4377    }
4378    /* otherwise, continue */
4379
4380    log_msg(1, "DEFINITELY restoring %s", biggiestruct.filename);
4381    if (biggiestruct.use_ntfsprog) {
4382        if (strncmp(biggiestruct.filename, "/dev/", 5)) {
4383            log_msg(1,
4384                    "I was in error when I set biggiestruct.use_ntfsprog to TRUE.");
4385            log_msg(1, "%s isn't even in /dev", biggiestruct.filename);
4386            biggiestruct.use_ntfsprog = FALSE;
4387        }
4388    }
4389
4390    if (biggiestruct.use_ntfsprog)  // if it's an NTFS device
4391//  if (!strncmp ( biggiestruct.filename, "/dev/", 5))
4392    {
4393        g_loglevel = 4;
4394        use_ntfsprog_hack = TRUE;
4395        log_msg(2,
4396                "Calling ntfsclone in background because %s is an NTFS /dev entry",
4397                outfile_fname);
4398        sprintf(sz_devfile, "/tmp/%d.%d.000", (int) (random() % 32768),
4399                (int) (random() % 32768));
4400        mkfifo(sz_devfile, 0x770);
4401        strcpy(ntfsprog_fifo, sz_devfile);
4402        file_to_openout = ntfsprog_fifo;
4403        switch (pid = fork()) {
4404        case -1:
4405            fatal_error("Fork failure");
4406        case 0:
4407            log_msg(3,
4408                    "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)",
4409                    biggiestruct.filename, ntfsprog_fifo);
4410            res =
4411                feed_outfrom_ntfsprog(biggiestruct.filename,
4412                                       ntfsprog_fifo);
4413//          log_msg(3, "CHILD - fip - exiting");
4414            exit(res);
4415            break;
4416        default:
4417            log_msg(3,
4418                    "feed_into_ntfsprog() called in background --- pid=%ld",
4419                    (long int) (pid));
4420        }
4421    } else {
4422        use_ntfsprog_hack = FALSE;
4423        ntfsprog_fifo[0] = '\0';
4424        file_to_openout = outfile_fname;
4425        if (!does_file_exist(outfile_fname))    // yes, it looks weird with the '!' but it's correct that way
4426        {
4427            make_hole_for_file(outfile_fname);
4428        }
4429    }
4430
4431    sprintf(tmp, "Reassembling big file %ld (%s)", bigfileno + 1,
4432            outfile_fname);
4433    log_msg(2, tmp);
4434
4435    /*
4436       last slice is zero-length and uncompressed; when we find it, we stop.
4437       We DON'T wait until there are no more slices; if we did that,
4438       We might stop at end of CD, not at last slice (which is 0-len and uncompd)
4439     */
4440
4441    strncpy(pathname_of_last_file_restored, biggiestruct.filename,
4442            MAX_STR_LEN - 1);
4443    pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0';
4444
4445    log_msg(3, "file_to_openout = %s", file_to_openout);
4446    if (!(fout = fopen(file_to_openout, "w"))) {
4447        log_to_screen("Cannot openout outfile_fname - hard disk full?");
4448        return (1);
4449    }
4450    log_msg(3, "Opened out to %s", outfile_fname);  // CD/DVD --> mondorestore --> ntfsclone --> hard disk itself
4451
4452    for (sliceno = 1, finished = FALSE; !finished;) {
4453        if (!does_file_exist
4454            (slice_fname(bigfileno, sliceno, ARCHIVES_PATH, ""))
4455            &&
4456            !does_file_exist(slice_fname
4457                             (bigfileno, sliceno, ARCHIVES_PATH, "lzo"))
4458            &&
4459            !does_file_exist(slice_fname
4460                             (bigfileno, sliceno, ARCHIVES_PATH, "gz"))
4461            &&
4462            !does_file_exist(slice_fname
4463                             (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) {
4464            log_msg(3,
4465                    "Cannot find a data slice or terminator slice on CD %d",
4466                    g_current_media_number);
4467            g_current_media_number++;
4468            sprintf(tmp,
4469                    "Asking for %s #%d so that I may read slice #%ld\n",
4470                    media_descriptor_string(bkpinfo->backup_media_type),
4471                    g_current_media_number, sliceno);
4472            log_msg(2, tmp);
4473            sprintf(tmp, "Restoring from %s #%d",
4474                    media_descriptor_string(bkpinfo->backup_media_type),
4475                    g_current_media_number);
4476            log_to_screen(tmp);
4477            insist_on_this_cd_number(g_current_media_number);
4478            log_to_screen("Continuing to restore.");
4479        } else {
4480            strcpy(tmp,
4481                   slice_fname(bigfileno, sliceno, ARCHIVES_PATH, ""));
4482            if (does_file_exist(tmp) && length_of_file(tmp) == 0) {
4483                log_msg(2,
4484                        "End of bigfile # %ld (slice %ld is the terminator)",
4485                        bigfileno + 1, sliceno);
4486                finished = TRUE;
4487                continue;
4488            } else {
4489                if (does_file_exist
4490                    (slice_fname
4491                     (bigfileno, sliceno, ARCHIVES_PATH, "lzo"))) {
4492                    strcpy(bzip2_command, "lzop");
4493                    strcpy(suffix, "lzo");
4494                } else
4495                    if (does_file_exist
4496                        (slice_fname
4497                         (bigfileno, sliceno, ARCHIVES_PATH, "gz"))) {
4498                    strcpy(bzip2_command, "gzip");
4499                    strcpy(suffix, "gz");
4500                } else
4501                    if (does_file_exist
4502                        (slice_fname
4503                         (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) {
4504                    strcpy(bzip2_command, "bzip2");
4505                    strcpy(suffix, "bz2");
4506                } else
4507                    if (does_file_exist
4508                        (slice_fname
4509                         (bigfileno, sliceno, ARCHIVES_PATH, ""))) {
4510                    strcpy(bzip2_command, "");
4511                    strcpy(suffix, "");
4512                } else {
4513                    log_to_screen("OK, that's pretty fsck0red...");
4514                    return (1);
4515                }
4516            }
4517            if (bzip2_command[0] != '\0') {
4518                sprintf(bzip2_command + strlen(bzip2_command),
4519                        " -dc %s 2>> %s",
4520                        slice_fname(bigfileno, sliceno, ARCHIVES_PATH,
4521                                    suffix), MONDO_LOGFILE);
4522            } else {
4523                sprintf(bzip2_command, "cat %s 2>> %s",
4524                        slice_fname(bigfileno, sliceno, ARCHIVES_PATH,
4525                                    suffix), MONDO_LOGFILE);
4526            }
4527            sprintf(tmp, "Working on %s #%d, file #%ld, slice #%ld    ",
4528                    media_descriptor_string(bkpinfo->backup_media_type),
4529                    g_current_media_number, bigfileno + 1, sliceno);
4530            log_msg(2, tmp);
4531
4532            if (!g_text_mode) {
4533                newtDrawRootText(0, g_noof_rows - 2, tmp);
4534                newtRefresh();
4535                strip_spaces(tmp);
4536                update_progress_form(tmp);
4537            }
4538            if (!(fbzip2 = popen(bzip2_command, "r"))) {
4539                fatal_error("Can't run popen command");
4540            }
4541            while (!feof(fbzip2)) {
4542                siz = fread(bigblk, 1, TAPE_BLOCK_SIZE, fbzip2);
4543                if (siz > 0) {
4544                    sprintf(sz_msg, "Read %ld from fbzip2", siz);
4545                    siz = fwrite(bigblk, 1, siz, fout);
4546                    sprintf(sz_msg + strlen(sz_msg),
4547                            "; written %ld to fout", siz);
4548//        log_msg(2. sz_msg);
4549                }
4550            }
4551            paranoid_pclose(fbzip2);
4552
4553
4554            sliceno++;
4555            g_current_progress++;
4556        }
4557    }
4558/*
4559  memset(bigblk, TAPE_BLOCK_SIZE, 1); // This all looks very fishy...
4560  fwrite( bigblk, 1, TAPE_BLOCK_SIZE, fout);
4561  fwrite( bigblk, 1, TAPE_BLOCK_SIZE, fout);
4562  fwrite( bigblk, 1, TAPE_BLOCK_SIZE, fout);
4563  fwrite( bigblk, 1, TAPE_BLOCK_SIZE, fout);
4564*/
4565    paranoid_fclose(fout);
4566    g_loglevel = old_loglevel;
4567
4568    if (use_ntfsprog_hack) {
4569        log_msg(3, "Waiting for ntfsclone to finish");
4570        sprintf(tmp,
4571                " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null");
4572        while (system(tmp) == 0) {
4573            sleep(1);
4574        }
4575        log_it("OK, ntfsclone has really finished");
4576    }
4577
4578    if (strcmp(outfile_fname, "/dev/null")) {
4579        chown(outfile_fname, biggiestruct.properties.st_uid,
4580              biggiestruct.properties.st_gid);
4581        chmod(outfile_fname, biggiestruct.properties.st_mode);
4582        ubuf->actime = biggiestruct.properties.st_atime;
4583        ubuf->modtime = biggiestruct.properties.st_mtime;
4584        utime(outfile_fname, ubuf);
4585    }
4586    paranoid_free(bigblk);
4587    paranoid_free(checksum);
4588    paranoid_free(outfile_fname);
4589    paranoid_free(tmp);
4590    paranoid_free(bzip2_command);
4591    paranoid_free(ntfsprog_command);
4592    paranoid_free(suffix);
4593    paranoid_free(sz_devfile);
4594
4595    return (retval);
4596}
4597
4598/**************************************************************************
4599 *END_ RESTORE_A_BIGGIEFILE_FROM_CD                                       *
4600 **************************************************************************/
4601
4602
4603
4604/**
4605 * Restore a biggiefile from the currently opened stream.
4606 * @param bkpinfo The backup information structure. Fields used:
4607 * - @c bkpinfo->restore_path
4608 * - @c bkpinfo->zip_exe
4609 * @param orig_bf_fname The original filename of the biggiefile.
4610 * @param biggiefile_number The number of the biggiefile (starting from 0).
4611 * @param orig_checksum Unused.
4612 * @param biggiefile_size Unused.
4613 * @param filelist The node structure containing the list of files to be restored.
4614 * If @p orig_bf_fname is not in the list, it will be ignored.
4615 * @return 0 for success (or skip), nonzero for failure.
4616 * @bug orig_checksum and biggiefile_size are unused (except to check that they are non-NULL).
4617 */
4618int restore_a_biggiefile_from_stream(char *orig_bf_fname, long biggiefile_number, char *orig_checksum,  //UNUSED
4619                                     long long biggiefile_size, //UNUSED
4620                                     struct s_node *filelist,
4621                                     int use_ntfsprog,
4622                                     char *pathname_of_last_file_restored)
4623{
4624    FILE *pout;
4625    FILE *fin;
4626
4627  /** mallocs ********/
4628    char *tmp;
4629    char *command;
4630    char *outfile_fname;
4631    char *ntfsprog_command;
4632    char *sz_devfile;
4633    char *ntfsprog_fifo;
4634    char *file_to_openout = NULL;
4635
4636    struct s_node *node;
4637
4638    int old_loglevel;
4639    long current_slice_number = 0;
4640    int retval = 0;
4641    int res = 0;
4642    int ctrl_chr = '\0';
4643    long long slice_siz;
4644    bool dummy_restore = FALSE;
4645    bool use_ntfsprog_hack = FALSE;
4646    pid_t pid;
4647    struct s_filename_and_lstat_info biggiestruct;
4648    struct utimbuf the_utime_buf, *ubuf;
4649    ubuf = &the_utime_buf;
4650
4651    malloc_string(tmp);
4652    malloc_string(ntfsprog_fifo);
4653    malloc_string(outfile_fname);
4654    malloc_string(command);
4655    malloc_string(sz_devfile);
4656    malloc_string(ntfsprog_command);
4657    old_loglevel = g_loglevel;
4658    assert(bkpinfo != NULL);
4659    assert(orig_bf_fname != NULL);
4660    assert(orig_checksum != NULL);
4661
4662    pathname_of_last_file_restored[0] = '\0';
4663    if (use_ntfsprog == BLK_START_A_PIHBIGGIE) {
4664        use_ntfsprog = 1;
4665        log_msg(1, "%s --- pih=YES", orig_bf_fname);
4666    } else if (use_ntfsprog == BLK_START_A_NORMBIGGIE) {
4667        use_ntfsprog = 0;
4668        log_msg(1, "%s --- pih=NO", orig_bf_fname);
4669    } else {
4670        use_ntfsprog = 0;
4671        log_msg(1, "%s --- pih=NO (weird marker though)", orig_bf_fname);
4672    }
4673
4674    strncpy(pathname_of_last_file_restored, orig_bf_fname,
4675            MAX_STR_LEN - 1);
4676    pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0';
4677
4678    /* open out to biggiefile to be restored (or /dev/null if biggiefile is not to be restored) */
4679
4680    if (filelist != NULL) {
4681        node = find_string_at_node(filelist, orig_bf_fname);
4682        if (!node) {
4683            dummy_restore = TRUE;
4684            log_msg(1,
4685                    "Skipping big file %ld (%s) - not in biggielist subset",
4686                    biggiefile_number + 1, orig_bf_fname);
4687            pathname_of_last_file_restored[0] = '\0';
4688        } else if (!(node->selected)) {
4689            dummy_restore = TRUE;
4690            log_msg(1, "Skipping %s (name isn't in biggielist subset)",
4691                    orig_bf_fname);
4692            pathname_of_last_file_restored[0] = '\0';
4693        }
4694    }
4695
4696    if (use_ntfsprog) {
4697        if (strncmp(orig_bf_fname, "/dev/", 5)) {
4698            log_msg(1,
4699                    "I was in error when I set use_ntfsprog to TRUE.");
4700            log_msg(1, "%s isn't even in /dev", orig_bf_fname);
4701            use_ntfsprog = FALSE;
4702        }
4703    }
4704
4705    if (use_ntfsprog) {
4706        g_loglevel = 4;
4707        strcpy(outfile_fname, orig_bf_fname);
4708        use_ntfsprog_hack = TRUE;
4709        log_msg(2,
4710                "Calling ntfsclone in background because %s is a /dev entry",
4711                outfile_fname);
4712        sprintf(sz_devfile, "%s/%d.%d.000", 
4713                bkpinfo->tmpdir,
4714                (int) (random() % 32768),
4715                (int) (random() % 32768));
4716        mkfifo(sz_devfile, 0x770);
4717        strcpy(ntfsprog_fifo, sz_devfile);
4718        file_to_openout = ntfsprog_fifo;
4719        switch (pid = fork()) {
4720        case -1:
4721            fatal_error("Fork failure");
4722        case 0:
4723            log_msg(3,
4724                    "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)",
4725                    outfile_fname, ntfsprog_fifo);
4726            res =
4727                feed_outfrom_ntfsprog(outfile_fname, ntfsprog_fifo);
4728//          log_msg(3, "CHILD - fip - exiting");
4729            exit(res);
4730            break;
4731        default:
4732            log_msg(3,
4733                    "feed_into_ntfsprog() called in background --- pid=%ld",
4734                    (long int) (pid));
4735        }
4736    } else {
4737        if (!strncmp(orig_bf_fname, "/dev/", 5))    // non-NTFS partition
4738        {
4739            strcpy(outfile_fname, orig_bf_fname);
4740        } else                  // biggiefile
4741        {
4742            sprintf(outfile_fname, "%s/%s", bkpinfo->restore_path,
4743                    orig_bf_fname);
4744        }
4745        use_ntfsprog_hack = FALSE;
4746        ntfsprog_fifo[0] = '\0';
4747        file_to_openout = outfile_fname;
4748        if (!does_file_exist(outfile_fname))    // yes, it looks weird with the '!' but it's correct that way
4749        {
4750            make_hole_for_file(outfile_fname);
4751        }
4752        sprintf(tmp, "Reassembling big file %ld (%s)",
4753                biggiefile_number + 1, orig_bf_fname);
4754        log_msg(2, tmp);
4755    }
4756
4757    if (dummy_restore) {
4758        sprintf(outfile_fname, "/dev/null");
4759    }
4760
4761    if (!bkpinfo->zip_exe[0]) {
4762        sprintf(command, "cat > \"%s\"", file_to_openout);
4763    } else {
4764        sprintf(command, "%s -dc > \"%s\" 2>> %s", bkpinfo->zip_exe,
4765                file_to_openout, MONDO_LOGFILE);
4766        if (strcmp(bkpinfo->zip_exe, "gzip") == 0) {
4767            /* Ignore SIGPIPE for gzip as it causes errors on big files
4768             * Cf: http://trac.mondorescue.org/ticket/244
4769             */
4770            signal(SIGPIPE,SIG_IGN);
4771        }
4772    }
4773    sprintf(tmp, "Pipe command = '%s'", command);
4774    log_msg(3, tmp);
4775
4776    /* restore biggiefile, one slice at a time */
4777    if (!(pout = popen(command, "w"))) {
4778        fatal_error("Cannot pipe out");
4779    }
4780    for (res = read_header_block_from_stream(&slice_siz, tmp, &ctrl_chr);
4781         ctrl_chr != BLK_STOP_A_BIGGIE;
4782         res = read_header_block_from_stream(&slice_siz, tmp, &ctrl_chr)) {
4783        if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
4784            wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
4785        }
4786        sprintf(tmp, "Working on file #%ld, slice #%ld    ",
4787                biggiefile_number + 1, current_slice_number);
4788        log_msg(2, tmp);
4789        if (!g_text_mode) {
4790            newtDrawRootText(0, g_noof_rows - 2, tmp);
4791            newtRefresh();
4792        }
4793        strip_spaces(tmp);
4794        update_progress_form(tmp);
4795        if (current_slice_number == 0) {
4796            res =
4797                read_file_from_stream_to_file("/tmp/biggie-blah.txt",
4798                                              slice_siz);
4799            if (!(fin = fopen("/tmp/biggie-blah.txt", "r"))) {
4800                log_OS_error("blah blah");
4801            } else {
4802                if (fread
4803                    ((void *) &biggiestruct, 1, sizeof(biggiestruct),
4804                     fin) < sizeof(biggiestruct)) {
4805                    log_msg(2,
4806                            "Warning - unable to get biggiestruct of bigfile #%d",
4807                            biggiefile_number + 1);
4808                }
4809                paranoid_fclose(fin);
4810            }
4811        } else {
4812            res =
4813                read_file_from_stream_to_stream(pout, slice_siz);
4814        }
4815        retval += res;
4816        res = read_header_block_from_stream(&slice_siz, tmp, &ctrl_chr);
4817        if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
4818            wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
4819        }
4820        current_slice_number++;
4821        g_current_progress++;
4822    }
4823    paranoid_pclose(pout);
4824
4825    if (bkpinfo->zip_exe[0]) {
4826        if (strcmp(bkpinfo->zip_exe, "gzip") == 0) {
4827            /* Re-enable SIGPIPE for gzip
4828             */
4829            signal(SIGPIPE, terminate_daemon);
4830        }
4831    }
4832
4833    log_msg(1, "pathname_of_last_file_restored is now %s",
4834            pathname_of_last_file_restored);
4835
4836    if (use_ntfsprog_hack) {
4837        log_msg(3, "Waiting for ntfsclone to finish");
4838        sprintf(tmp,
4839                " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null");
4840        while (system(tmp) == 0) {
4841            sleep(1);
4842        }
4843        log_msg(3, "OK, ntfsclone has really finished");
4844    }
4845
4846    log_msg(3, "biggiestruct.filename = %s", biggiestruct.filename);
4847    log_msg(3, "biggiestruct.checksum = %s", biggiestruct.checksum);
4848    if (strcmp(outfile_fname, "/dev/null")) {
4849        chmod(outfile_fname, biggiestruct.properties.st_mode);
4850        chown(outfile_fname, biggiestruct.properties.st_uid,
4851              biggiestruct.properties.st_gid);
4852        ubuf->actime = biggiestruct.properties.st_atime;
4853        ubuf->modtime = biggiestruct.properties.st_mtime;
4854        utime(outfile_fname, ubuf);
4855    }
4856
4857    paranoid_free(tmp);
4858    paranoid_free(outfile_fname);
4859    paranoid_free(command);
4860    paranoid_free(ntfsprog_command);
4861    paranoid_free(sz_devfile);
4862    paranoid_free(ntfsprog_fifo);
4863    g_loglevel = old_loglevel;
4864    return (retval);
4865}
4866
4867/**************************************************************************
4868 *END_RESTORE_A_BIGGIEFILE_FROM_STREAM                                    *
4869 **************************************************************************/
4870
4871
4872
4873/**
4874 * Restore @p tarball_fname from CD.
4875 * @param tarball_fname The filename of the tarball to restore (in /mnt/cdrom).
4876 * This will be used unmodified.
4877 * @param current_tarball_number The number (starting from 0) of the fileset
4878 * we're restoring now.
4879 * @param filelist The node structure containing the list of files to be
4880 * restored. If no file in the afioball is in this list, afio will still be
4881 * called, but nothing will be written.
4882 * @return 0 for success, nonzero for failure.
4883 */
4884int
4885restore_a_tarball_from_CD(char *tarball_fname,
4886                          long current_tarball_number,
4887                          struct s_node *filelist)
4888{
4889    int retval = 0;
4890    int res;
4891    char *p;
4892
4893  /** malloc **/
4894    char *command;
4895    char *tmp;
4896    char *filelist_name;
4897    char *filelist_subset_fname;
4898    char *executable;
4899    char *temp_log;
4900    char screen_message[100];
4901    long matches = 0;
4902    bool use_star;
4903    char *xattr_fname;
4904    char *acl_fname;
4905//  char files_to_restore_this_time_fname[MAX_STR_LEN];
4906
4907    assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
4908    malloc_string(command);
4909    malloc_string(tmp);
4910    malloc_string(filelist_name);
4911    malloc_string(filelist_subset_fname);
4912    malloc_string(executable);
4913    malloc_string(temp_log);
4914    malloc_string(xattr_fname);
4915    malloc_string(acl_fname);
4916
4917    log_msg(5, "Entering");
4918    filelist_subset_fname[0] = '\0';
4919    use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE;
4920//  sprintf(files_to_restore_this_time_fname, "/tmp/ftrttf.%d.%d", (int)getpid(), (int)random());
4921    sprintf(command, "mkdir -p %s/tmp", MNT_RESTORING);
4922    run_program_and_log_output(command, 9);
4923    sprintf(temp_log, "/tmp/%d.%d", (int) (random() % 32768),
4924            (int) (random() % 32768));
4925
4926    sprintf(filelist_name, MNT_CDROM "/archives/filelist.%ld",
4927            current_tarball_number);
4928    if (length_of_file(filelist_name) <= 2) {
4929        log_msg(2, "There are _zero_ files in filelist '%s'",
4930                filelist_name);
4931        log_msg(2,
4932                "This is a bit silly (ask dev-team to fix mondo_makefilelist, please)");
4933        log_msg(2,
4934                "but it's non-critical. It's cosmetic. Don't worry about it.");
4935        retval = 0;
4936        goto leave_sub;
4937    }
4938    if (count_lines_in_file(filelist_name) <= 0
4939        || length_of_file(tarball_fname) <= 0) {
4940        log_msg(3, "length_of_file(%s) = %llu", tarball_fname,
4941                length_of_file(tarball_fname));
4942        sprintf(tmp, "Unable to restore fileset #%ld (CD I/O error)",
4943                current_tarball_number);
4944        log_to_screen(tmp);
4945        retval = 1;
4946        goto leave_sub;
4947    }
4948
4949    if (filelist) {
4950        sprintf(filelist_subset_fname, "/tmp/filelist-subset-%ld.tmp",
4951                current_tarball_number);
4952        if ((matches =
4953             save_filelist_entries_in_common(filelist_name, filelist,
4954                                             filelist_subset_fname,
4955                                             use_star))
4956            <= 0) {
4957            sprintf(tmp, "Skipping fileset %ld", current_tarball_number);
4958            log_msg(1, tmp);
4959        } else {
4960            log_msg(3, "Saved fileset %ld's subset to %s",
4961                    current_tarball_number, filelist_subset_fname);
4962        }
4963        sprintf(screen_message, "Tarball #%ld --- %ld matches",
4964                current_tarball_number, matches);
4965        log_to_screen(screen_message);
4966    } else {
4967        filelist_subset_fname[0] = '\0';
4968    }
4969
4970    if (filelist == NULL || matches > 0) {
4971        if (g_getfattr) {
4972            sprintf(xattr_fname, XATTR_LIST_FNAME_RAW_SZ,
4973                MNT_CDROM "/archives", current_tarball_number);
4974        }
4975        if (g_getfacl) {
4976            sprintf(acl_fname, ACL_LIST_FNAME_RAW_SZ, MNT_CDROM "/archives",
4977                current_tarball_number);
4978        }
4979        if (strstr(tarball_fname, ".bz2")) {
4980            strcpy(executable, "bzip2");
4981        } else if (strstr(tarball_fname, ".gz")) {
4982            strcpy(executable, "gzip");
4983        } else if (strstr(tarball_fname, ".lzo")) {
4984            strcpy(executable, "lzop");
4985        } else {
4986            executable[0] = '\0';
4987        }
4988        if (executable[0]) {
4989            sprintf(tmp, "which %s > /dev/null 2> /dev/null", executable);
4990            if (run_program_and_log_output(tmp, FALSE)) {
4991                log_to_screen
4992                    ("(compare_a_tarball) Compression program not found - oh no!");
4993                paranoid_MR_finish(1);
4994            }
4995            strcpy(tmp, executable);
4996            sprintf(executable, "-P %s -Z", tmp);
4997        }
4998#ifdef __FreeBSD__
4999#define BUFSIZE 512
5000#else
5001#define BUFSIZE (1024L*1024L)/TAPE_BLOCK_SIZE
5002#endif
5003
5004//      if (strstr(tarball_fname, ".star."))
5005        if (use_star) {
5006            sprintf(command,
5007                    "star -x -force-remove -U " STAR_ACL_SZ
5008                    " errctl= file=%s", tarball_fname);
5009            if (strstr(tarball_fname, ".bz2")) {
5010                strcat(command, " -bz");
5011            }
5012        } else {
5013            if (filelist_subset_fname[0] != '\0') {
5014                sprintf(command,
5015                        "afio -i -M 8m -b %ld -c %ld %s -w '%s' %s",
5016                        TAPE_BLOCK_SIZE,
5017                        BUFSIZE, executable, filelist_subset_fname,
5018//             files_to_restore_this_time_fname,
5019                        tarball_fname);
5020            } else {
5021                sprintf(command,
5022                        "afio -i -b %ld -c %ld -M 8m %s %s",
5023                        TAPE_BLOCK_SIZE,
5024                        BUFSIZE, executable, tarball_fname);
5025            }
5026        }
5027#undef BUFSIZE
5028        sprintf(command + strlen(command), " 2>> %s >> %s", temp_log,
5029                temp_log);
5030        log_msg(1, "command = '%s'", command);
5031        unlink(temp_log);
5032        res = system(command);
5033        if (res) {
5034            p = strstr(command, "-acl ");
5035            if (p) {
5036                p[0] = p[1] = p[2] = p[3] = ' ';
5037                log_msg(1, "new command = '%s'", command);
5038                res = system(command);
5039            }
5040        }
5041        if (res && length_of_file(temp_log) < 5) {
5042            res = 0;
5043        }
5044
5045        if (g_getfattr) {
5046            log_msg(1, "Setting fattr list %s", xattr_fname);
5047            if (length_of_file(xattr_fname) > 0) {
5048                res = set_fattr_list(filelist_subset_fname, xattr_fname);
5049                if (res) {
5050                    log_to_screen
5051                        ("Errors occurred while setting extended attributes");
5052                } else {
5053                    log_msg(1, "I set xattr OK");
5054                }
5055                retval += res;
5056            }
5057        }
5058        if (g_getfacl) {
5059            log_msg(1, "Setting acl list %s", acl_fname);
5060            if (length_of_file(acl_fname) > 0) {
5061                res = set_acl_list(filelist_subset_fname, acl_fname);
5062                if (res) {
5063                    log_to_screen
5064                        ("Errors occurred while setting access control lists");
5065                } else {
5066                    log_msg(1, "I set ACL OK");
5067                }
5068                retval += res;
5069            }
5070        }
5071        if (retval) {
5072            sprintf(command, "cat %s >> %s", temp_log, MONDO_LOGFILE);
5073            system(command);
5074            log_msg(2, "Errors occurred while processing fileset #%d",
5075                    current_tarball_number);
5076        } else {
5077            log_msg(2, "Fileset #%d processed OK", current_tarball_number);
5078        }
5079    }
5080    if (does_file_exist("/PAUSE")) {
5081        popup_and_OK
5082            ("Press ENTER to go on. Delete /PAUSE to stop these pauses.");
5083    }
5084    unlink(filelist_subset_fname);
5085    unlink(xattr_fname);
5086    unlink(acl_fname);
5087    unlink(temp_log);
5088
5089  leave_sub:
5090    paranoid_free(command);
5091    paranoid_free(tmp);
5092    paranoid_free(filelist_name);
5093    paranoid_free(filelist_subset_fname);
5094    paranoid_free(executable);
5095    paranoid_free(temp_log);
5096    paranoid_free(xattr_fname);
5097    paranoid_free(acl_fname);
5098    log_msg(5, "Leaving");
5099    return (retval);
5100}
5101
5102/**************************************************************************
5103 *END_RESTORE_A_TARBALL_FROM_CD                                           *
5104 **************************************************************************/
5105
5106
5107/**
5108 * Restore a tarball from the currently opened stream.
5109 * @param bkpinfo The backup information structure. Fields used:
5110 * - @c bkpinfo->backup_media_type
5111 * - @c bkpinfo->media_device
5112 * - @c bkpinfo->zip_exe
5113 * @param tarball_fname The filename of the afioball to restore.
5114 * @param current_tarball_number The number (starting from 0) of the fileset
5115 * we're restoring now.
5116 * @param filelist The node structure containing the list of files to be
5117 * restored. If no file in the afioball is in this list, afio will still be
5118 * called, but nothing will be written.
5119 * @param size The size (in @b bytes) of the afioball.
5120 * @return 0 for success, nonzero for failure.
5121 */
5122int
5123restore_a_tarball_from_stream(char *tarball_fname,
5124                              long current_tarball_number,
5125                              struct s_node *filelist,
5126                              long long size, char *xattr_fname,
5127                              char *acl_fname)
5128{
5129    int retval = 0;
5130    int res = 0;
5131
5132  /** malloc add ***/
5133    char *tmp;
5134    char *command;
5135    char *afio_fname;
5136    char *filelist_fname;
5137    char *filelist_subset_fname;
5138    char *executable;
5139    long matches = 0;
5140    bool restore_this_fileset = FALSE;
5141    bool use_star;
5142
5143    assert(bkpinfo != NULL);
5144    assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
5145    malloc_string(filelist_subset_fname);
5146    malloc_string(filelist_fname);
5147    malloc_string(afio_fname);
5148    malloc_string(executable);
5149    malloc_string(command);
5150    malloc_string(tmp);
5151    filelist_subset_fname[0] = '\0';
5152    /* to do it with a file... */
5153    use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE;
5154    sprintf(tmp,
5155            "Restoring from fileset #%ld (%ld KB) on %s #%d",
5156            current_tarball_number, (long) size >> 10,
5157            media_descriptor_string(bkpinfo->backup_media_type),
5158            g_current_media_number);
5159    log_msg(2, tmp);
5160    run_program_and_log_output("mkdir -p " MNT_RESTORING "/tmp", FALSE);
5161
5162  /****************************************************************************
5163   * Use RAMDISK's /tmp; saves time; oh wait, it's too small                  *
5164   * Well, pipe from tape to afio, then; oh wait, can't do that either: bug   *
5165   * in afio or someting; oh darn.. OK, use tmpfs :-)                         *
5166   ****************************************************************************/
5167    filelist_fname[0] = filelist_subset_fname[0] = '\0';
5168    sprintf(afio_fname, "/tmp/tmpfs/archive.tmp.%ld",
5169            current_tarball_number);
5170    sprintf(filelist_fname, "%s/filelist.%ld", bkpinfo->tmpdir,
5171            current_tarball_number);
5172    sprintf(filelist_subset_fname, "%s/filelist-subset-%ld.tmp",
5173            bkpinfo->tmpdir, current_tarball_number);
5174//  sprintf(filelist_fname, "/tmp/tmpfs/temp-filelist.%ld", current_tarball_number);
5175    res = read_file_from_stream_to_file(afio_fname, size);
5176    if (strstr(tarball_fname, ".star")) {
5177        bkpinfo->use_star = TRUE;
5178    }
5179    if (res) {
5180        log_msg(1, "Warning - error reading afioball from tape");
5181    }
5182    if (bkpinfo->compression_level == 0) {
5183        executable[0] = '\0';
5184    } else {
5185        if (bkpinfo->use_star) {
5186            strcpy(executable, " -bz");
5187        } else {
5188            sprintf(executable, "-P %s -Z", bkpinfo->zip_exe);
5189        }
5190    }
5191
5192    if (!filelist)              // if unconditional restore then restore entire fileset
5193    {
5194        restore_this_fileset = TRUE;
5195    } else                      // If restoring selectively then get TOC from tarball
5196    {
5197        if (strstr(tarball_fname, ".star.")) {
5198            use_star = TRUE;
5199            sprintf(command, "star -t file=%s %s", afio_fname, executable);
5200        } else {
5201            use_star = FALSE;
5202            sprintf(command, "afio -t -M 8m -b %ld %s %s", TAPE_BLOCK_SIZE,
5203                    executable, afio_fname);
5204        }
5205        sprintf(command + strlen(command), " > %s 2>> %s", filelist_fname,
5206                MONDO_LOGFILE);
5207        log_msg(1, "command = %s", command);
5208        if (system(command)) {
5209            log_msg(4, "Warning - error occurred while retrieving TOC");
5210        }
5211        if ((matches =
5212             save_filelist_entries_in_common(filelist_fname, filelist,
5213                                             filelist_subset_fname,
5214                                             use_star))
5215            <= 0 || length_of_file(filelist_subset_fname) < 2) {
5216            if (length_of_file(filelist_subset_fname) < 2) {
5217                log_msg(1, "No matches found in fileset %ld",
5218                        current_tarball_number);
5219            }
5220            sprintf(tmp, "Skipping fileset %ld", current_tarball_number);
5221            log_msg(2, tmp);
5222            restore_this_fileset = FALSE;
5223        } else {
5224            log_msg(5, "%ld matches. Saved fileset %ld's subset to %s",
5225                    matches, current_tarball_number,
5226                    filelist_subset_fname);
5227            restore_this_fileset = TRUE;
5228        }
5229    }
5230
5231// Concoct the call to star/afio to restore files
5232    if (strstr(tarball_fname, ".star."))    // star
5233    {
5234        sprintf(command, "star -x file=%s %s", afio_fname, executable);
5235        if (filelist) {
5236            sprintf(command + strlen(command), " list=%s",
5237                    filelist_subset_fname);
5238        }
5239    } else                      // afio
5240    {
5241        sprintf(command, "afio -i -M 8m -b %ld %s", TAPE_BLOCK_SIZE,
5242                executable);
5243        if (filelist) {
5244            sprintf(command + strlen(command), " -w %s",
5245                    filelist_subset_fname);
5246        }
5247        sprintf(command + strlen(command), " %s", afio_fname);
5248    }
5249    sprintf(command + strlen(command), " 2>> %s", MONDO_LOGFILE);
5250
5251// Call if IF there are files to restore (selectively/unconditionally)
5252    if (restore_this_fileset) {
5253        log_msg(1, "Calling command='%s'", command);
5254        paranoid_system(command);
5255
5256        if (g_getfattr) {
5257            iamhere("Restoring xattr stuff");
5258            res = set_fattr_list(filelist_subset_fname, xattr_fname);
5259            if (res) {
5260                log_msg(1, "Errors occurred while setting xattr");
5261            } else {
5262                log_msg(1, "I set xattr OK");
5263            }
5264            retval += res;
5265        }
5266
5267        if (g_getfacl) {
5268            iamhere("Restoring acl stuff");
5269            res = set_acl_list(filelist_subset_fname, acl_fname);
5270            if (res) {
5271                log_msg(1, "Errors occurred while setting ACL");
5272            } else {
5273                log_msg(1, "I set ACL OK");
5274            }
5275            retval += res;
5276        }
5277
5278    } else {
5279        log_msg(1, "NOT CALLING '%s'", command);
5280    }
5281
5282    if (does_file_exist("/PAUSE") && current_tarball_number >= 50) {
5283        log_to_screen("Paused after set %ld", current_tarball_number);
5284        popup_and_OK("Pausing. Press ENTER to continue.");
5285    }
5286
5287    unlink(filelist_subset_fname);
5288    unlink(filelist_fname);
5289    unlink(afio_fname);
5290
5291    paranoid_free(filelist_subset_fname);
5292    paranoid_free(filelist_fname);
5293    paranoid_free(afio_fname);
5294    paranoid_free(command);
5295    paranoid_free(tmp);
5296    return (retval);
5297}
5298
5299/**************************************************************************
5300 *END_RESTORE_A_TARBALL_FROM_STREAM                                       *
5301 **************************************************************************/
5302
5303
5304
5305
5306/**
5307 * Restore all biggiefiles from all media in this CD backup.
5308 * The CD with the last afioball should be currently mounted.
5309 * @param bkpinfo The backup information structure. @c backup_media_type is the
5310 * only field used in this function.
5311 * @param filelist The node structure containing the list of files to be
5312 * restored. If a prospective biggiefile is not in this list, it will be ignored.
5313 * @return 0 for success, nonzero for failure.
5314 */
5315int
5316restore_all_biggiefiles_from_CD(struct s_node *filelist)
5317{
5318    int retval = 0;
5319    int res = 0;
5320    long noof_biggiefiles, bigfileno = 0, total_slices;
5321  /** malloc **/
5322    char *tmp;
5323    bool just_changed_cds = FALSE;
5324    char *xattr_fname;
5325    char *acl_fname;
5326    char *biggies_whose_EXATs_we_should_set;    // EXtended ATtributes
5327    char *pathname_of_last_biggie_restored;
5328    FILE *fbw = NULL;
5329
5330    malloc_string(xattr_fname);
5331    malloc_string(acl_fname);
5332    malloc_string(tmp);
5333    malloc_string(biggies_whose_EXATs_we_should_set);
5334    malloc_string(pathname_of_last_biggie_restored);
5335    assert(bkpinfo != NULL);
5336
5337    sprintf(biggies_whose_EXATs_we_should_set,
5338            "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir);
5339    if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) {
5340        log_msg(1, "Warning - cannot openout %s",
5341                biggies_whose_EXATs_we_should_set);
5342    }
5343
5344    read_cfg_var(g_mondo_cfg_file, "total-slices", tmp);
5345    total_slices = atol(tmp);
5346    sprintf(tmp, "Reassembling large files      ");
5347    mvaddstr_and_log_it(g_currentY, 0, tmp);
5348    if (length_of_file(BIGGIELIST) < 6) {
5349        log_msg(1, "OK, no biggielist; not restoring biggiefiles");
5350        return (0);
5351    }
5352    noof_biggiefiles = count_lines_in_file(BIGGIELIST);
5353    if (noof_biggiefiles <= 0) {
5354        log_msg(2,
5355                "OK, no biggiefiles in biggielist; not restoring biggiefiles");
5356        return (0);
5357    }
5358    sprintf(tmp, "OK, there are %ld biggiefiles in the archives",
5359            noof_biggiefiles);
5360    log_msg(2, tmp);
5361
5362    open_progress_form("Reassembling large files",
5363                       "I am now reassembling all the large files.",
5364                       "Please wait. This may take some time.",
5365                       "", total_slices);
5366    for (bigfileno = 0 ; bigfileno < noof_biggiefiles ;) {
5367        log_msg(2, "Thinking about restoring bigfile %ld", bigfileno + 1);
5368        if (!does_file_exist(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""))) {
5369            log_msg(3,
5370                    "...but its first slice isn't on this CD. Perhaps this was a selective restore?");
5371            log_msg(3, "Cannot find bigfile #%ld 's first slice on %s #%d",
5372                    bigfileno + 1,
5373                    media_descriptor_string(bkpinfo->backup_media_type),
5374                    g_current_media_number);
5375            log_msg(3, "Slicename would have been %s",
5376                    slice_fname(bigfileno, 0, ARCHIVES_PATH, ""));
5377            // I'm not positive 'just_changed_cds' is even necessary...
5378            if (just_changed_cds) {
5379                just_changed_cds = FALSE;
5380                log_msg(3,
5381                        "I'll continue to scan this CD for bigfiles to be restored.");
5382            } else if (does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST")) {
5383                insist_on_this_cd_number(++g_current_media_number);
5384                sprintf(tmp, "Restoring from %s #%d",
5385                        media_descriptor_string(bkpinfo->backup_media_type),
5386                        g_current_media_number);
5387                log_to_screen(tmp);
5388                just_changed_cds = TRUE;
5389            } else {
5390                /* That big file doesn't exist, but the followings may */
5391                /* So we need to continue looping */
5392                log_msg(2, "There was no bigfile #%ld. That's OK.",
5393                    bigfileno + 1);
5394                log_msg(2, "I'm going to stop restoring bigfiles now.");
5395                retval++;
5396                bigfileno++;
5397            }
5398        } else {
5399            just_changed_cds = FALSE;
5400            sprintf(tmp, "Restoring big file %ld", bigfileno + 1);
5401            update_progress_form(tmp);
5402            res =
5403                restore_a_biggiefile_from_CD(bigfileno, filelist, pathname_of_last_biggie_restored);
5404            iamhere(pathname_of_last_biggie_restored);
5405            if (fbw && pathname_of_last_biggie_restored[0]) {
5406                fprintf(fbw, "%s\n", pathname_of_last_biggie_restored);
5407            }
5408            retval += res;
5409            bigfileno++;
5410
5411        }
5412    }
5413
5414    if (fbw) {
5415        fclose(fbw);
5416        if (g_getfattr) {
5417            sprintf(xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH);
5418            if (length_of_file(xattr_fname) > 0) {
5419                set_fattr_list(biggies_whose_EXATs_we_should_set, xattr_fname);
5420            }
5421        }
5422        if (g_getfacl) {
5423            sprintf(acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH);
5424            if (length_of_file(acl_fname) > 0) {
5425                set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname);
5426            }
5427        }
5428    }
5429    if (does_file_exist("/PAUSE")) {
5430        popup_and_OK
5431            ("Press ENTER to go on. Delete /PAUSE to stop these pauses.");
5432    }
5433    close_progress_form();
5434    if (retval) {
5435        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
5436    } else {
5437        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
5438    }
5439    paranoid_free(xattr_fname);
5440    paranoid_free(acl_fname);
5441    paranoid_free(tmp);
5442    paranoid_free(biggies_whose_EXATs_we_should_set);
5443    paranoid_free(pathname_of_last_biggie_restored);
5444    return (retval);
5445}
5446
5447/**************************************************************************
5448 *END_RESTORE_ALL_BIGGIFILES_FROM_CD                                      *
5449 **************************************************************************/
5450
5451
5452
5453/**
5454 * Restore all afioballs from all CDs in the backup.
5455 * The first CD should be inserted (if not, it will be asked for).
5456 * @param bkpinfo The backup information structure. @c backup_media_type is the
5457 * only field used in @e this function.
5458 * @param filelist The node structure containing the list of files to be
5459 * restored. If no file in some particular afioball is in this list, afio will
5460 * still be called for that fileset, but nothing will be written.
5461 * @return 0 for success, or the number of filesets that failed.
5462 */
5463int
5464restore_all_tarballs_from_CD(struct s_node *filelist)
5465{
5466    int retval = 0;
5467    int res;
5468    int attempts;
5469    long current_tarball_number = 0;
5470    long max_val;
5471  /**malloc ***/
5472    char *tmp;
5473    char *tarball_fname;
5474    char *progress_str;
5475    char *comment;
5476
5477    malloc_string(tmp);
5478    malloc_string(tarball_fname);
5479    malloc_string(progress_str);
5480    malloc_string(comment);
5481
5482    assert(bkpinfo != NULL);
5483
5484    mvaddstr_and_log_it(g_currentY, 0, "Restoring from archives");
5485    log_msg(2,
5486            "Insisting on 1st CD, so that I can have a look at LAST-FILELIST-NUMBER");
5487    if (g_current_media_number != 1) {
5488        log_msg(3, "OK, that's jacked up.");
5489        g_current_media_number = 1;
5490    }
5491    insist_on_this_cd_number(g_current_media_number);
5492    read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp);
5493    max_val = atol(tmp) + 1;
5494    sprintf(progress_str, "Restoring from %s #%d",
5495            media_descriptor_string(bkpinfo->backup_media_type),
5496            g_current_media_number);
5497    log_to_screen(progress_str);
5498    open_progress_form("Restoring from archives",
5499                       "Restoring data from the archives.",
5500                       "Please wait. This may take some time.",
5501                       progress_str, max_val);
5502    for (;;) {
5503        insist_on_this_cd_number(g_current_media_number);
5504        update_progress_form(progress_str);
5505        sprintf(tarball_fname, MNT_CDROM "/archives/%ld.afio.bz2",
5506                current_tarball_number);
5507        if (!does_file_exist(tarball_fname)) {
5508            sprintf(tarball_fname, MNT_CDROM "/archives/%ld.afio.gz",
5509                current_tarball_number);
5510        }
5511        if (!does_file_exist(tarball_fname)) {
5512            sprintf(tarball_fname, MNT_CDROM "/archives/%ld.afio.lzo",
5513                    current_tarball_number);
5514        }
5515        if (!does_file_exist(tarball_fname)) {
5516            sprintf(tarball_fname, MNT_CDROM "/archives/%ld.afio.",
5517                    current_tarball_number);
5518        }
5519        if (!does_file_exist(tarball_fname)) {
5520            sprintf(tarball_fname, MNT_CDROM "/archives/%ld.star.bz2",
5521                    current_tarball_number);
5522        }
5523        if (!does_file_exist(tarball_fname)) {
5524            sprintf(tarball_fname, MNT_CDROM "/archives/%ld.star.",
5525                    current_tarball_number);
5526        }
5527        if (!does_file_exist(tarball_fname)) {
5528            if (current_tarball_number == 0) {
5529                log_to_screen
5530                    ("No tarballs. Strange. Maybe you only backed up freakin' big files?");
5531                return (0);
5532            }
5533            if (!does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST")
5534                || system("find " MNT_CDROM
5535                          "/archives/slice* > /dev/null 2> /dev/null") ==
5536                0) {
5537                break;
5538            }
5539            g_current_media_number++;
5540            sprintf(progress_str, "Restoring from %s #%d",
5541                    media_descriptor_string(bkpinfo->backup_media_type),
5542                    g_current_media_number);
5543            log_to_screen(progress_str);
5544        } else {
5545            sprintf(progress_str, "Restoring from fileset #%ld on %s #%d",
5546                    current_tarball_number,
5547                    media_descriptor_string(bkpinfo->backup_media_type),
5548                    g_current_media_number);
5549//    log_msg(3, "progress_str = %s", progress_str);
5550            for (res = 999, attempts = 0; attempts < 3 && res != 0;
5551                 attempts++) {
5552                res =
5553                    restore_a_tarball_from_CD(tarball_fname,
5554                                              current_tarball_number,
5555                                              filelist);
5556            }
5557            sprintf(tmp, "%s #%d, fileset #%ld - restore ",
5558                    media_descriptor_string(bkpinfo->backup_media_type),
5559                    g_current_media_number, current_tarball_number);
5560            if (res) {
5561                strcat(tmp, "reported errors");
5562            } else if (attempts > 1) {
5563                strcat(tmp, "succeeded");
5564            } else {
5565                strcat(tmp, "succeeded");
5566            }
5567            if (attempts > 1) {
5568                sprintf(tmp + strlen(tmp), " (%d attempts) - review logs",
5569                        attempts);
5570            }
5571            strcpy(comment, tmp);
5572            if (attempts > 1) {
5573                log_to_screen(comment);
5574            }
5575
5576            retval += res;
5577            current_tarball_number++;
5578            g_current_progress++;
5579        }
5580    }
5581    close_progress_form();
5582    if (retval) {
5583        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
5584    } else {
5585        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
5586    }
5587    paranoid_free(tmp);
5588    paranoid_free(tarball_fname);
5589    paranoid_free(progress_str);
5590    paranoid_free(comment);
5591
5592    return (retval);
5593}
5594
5595/**************************************************************************
5596 *END_RESTORE_ALL_TARBALLS_FROM_CD                                        *
5597 **************************************************************************/
5598
5599
5600
5601/**
5602 * Restore all biggiefiles from the currently opened stream.
5603 * @param bkpinfo The backup information structure. Passed to other functions.
5604 * @param filelist The node structure containing the list of files to be
5605 * restored. If a prospective biggiefile is not in the list, it will be ignored.
5606 * @return 0 for success, or the number of biggiefiles that failed.
5607 */
5608int
5609restore_all_biggiefiles_from_stream(struct s_node *filelist)
5610{
5611    long noof_biggiefiles;
5612    long current_bigfile_number = 0;
5613    long total_slices;
5614
5615    int retval = 0;
5616    int res = 0;
5617    int ctrl_chr;
5618
5619  /** malloc add ****/
5620    char *tmp;
5621    char *biggie_fname;
5622    char *biggie_cksum;
5623    char *xattr_fname;
5624    char *acl_fname;
5625    char *p;
5626    char *pathname_of_last_biggie_restored;
5627    char *biggies_whose_EXATs_we_should_set;    // EXtended ATtributes
5628    long long biggie_size;
5629    FILE *fbw = NULL;
5630
5631    malloc_string(tmp);
5632    malloc_string(biggie_fname);
5633    malloc_string(biggie_cksum);
5634    malloc_string(xattr_fname);
5635    malloc_string(acl_fname);
5636    malloc_string(biggies_whose_EXATs_we_should_set);
5637    malloc_string(pathname_of_last_biggie_restored);
5638    assert(bkpinfo != NULL);
5639
5640    read_cfg_var(g_mondo_cfg_file, "total-slices", tmp);
5641
5642    total_slices = atol(tmp);
5643    sprintf(tmp, "Reassembling large files      ");
5644    if (g_getfattr) {
5645        sprintf(xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
5646    }
5647    if (g_getfacl) {
5648        sprintf(acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
5649    }
5650    mvaddstr_and_log_it(g_currentY, 0, tmp);
5651    sprintf(biggies_whose_EXATs_we_should_set,
5652            "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir);
5653    if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) {
5654        log_msg(1, "Warning - cannot openout %s",
5655                biggies_whose_EXATs_we_should_set);
5656    }
5657// get xattr and acl files if they're there
5658    res =
5659        read_header_block_from_stream(&biggie_size, biggie_fname,
5660                                      &ctrl_chr);
5661    if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
5662        res =
5663            read_EXAT_files_from_tape(&biggie_size, biggie_fname,
5664                                      &ctrl_chr, xattr_fname, acl_fname);
5665    }
5666
5667    noof_biggiefiles = atol(biggie_fname);
5668    sprintf(tmp, "OK, there are %ld biggiefiles in the archives",
5669            noof_biggiefiles);
5670    log_msg(2, tmp);
5671    open_progress_form("Reassembling large files",
5672                       "I am now reassembling all the large files.",
5673                       "Please wait. This may take some time.",
5674                       "", total_slices);
5675
5676    for (res =
5677         read_header_block_from_stream(&biggie_size, biggie_fname,
5678                                       &ctrl_chr);
5679         ctrl_chr != BLK_STOP_BIGGIEFILES;
5680         res =
5681         read_header_block_from_stream(&biggie_size, biggie_fname,
5682                                       &ctrl_chr)) {
5683        if (ctrl_chr != BLK_START_A_NORMBIGGIE
5684            && ctrl_chr != BLK_START_A_PIHBIGGIE) {
5685            wrong_marker(BLK_START_A_NORMBIGGIE, ctrl_chr);
5686        }
5687        p = strrchr(biggie_fname, '/');
5688        if (!p) {
5689            p = biggie_fname;
5690        } else {
5691            p++;
5692        }
5693        sprintf(tmp, "Restoring big file %ld (%lld K)",
5694                current_bigfile_number + 1, biggie_size / 1024);
5695        update_progress_form(tmp);
5696        res = restore_a_biggiefile_from_stream(biggie_fname,
5697                                               current_bigfile_number,
5698                                               biggie_cksum,
5699                                               biggie_size,
5700                                               filelist, ctrl_chr,
5701                                               pathname_of_last_biggie_restored);
5702        log_msg(1, "I believe I have restored %s",
5703                pathname_of_last_biggie_restored);
5704        if (fbw && pathname_of_last_biggie_restored[0]) {
5705            fprintf(fbw, "%s\n", pathname_of_last_biggie_restored);
5706        }
5707        retval += res;
5708        current_bigfile_number++;
5709
5710    }
5711    if (current_bigfile_number != noof_biggiefiles
5712        && noof_biggiefiles != 0) {
5713        sprintf(tmp, "Warning - bigfileno=%ld but noof_biggiefiles=%ld\n",
5714                current_bigfile_number, noof_biggiefiles);
5715    } else {
5716        sprintf(tmp,
5717                "%ld biggiefiles in biggielist.txt; %ld biggiefiles processed today.",
5718                noof_biggiefiles, current_bigfile_number);
5719    }
5720    log_msg(1, tmp);
5721
5722    if (fbw) {
5723        fclose(fbw);
5724        if (length_of_file(biggies_whose_EXATs_we_should_set) > 2) {
5725            iamhere("Setting biggie-EXATs");
5726            if (g_getfattr) {
5727                if (length_of_file(xattr_fname) > 0) {
5728                    log_msg(1, "set_fattr_List(%s,%s)",
5729                        biggies_whose_EXATs_we_should_set, xattr_fname);
5730                    set_fattr_list(biggies_whose_EXATs_we_should_set,
5731                               xattr_fname);
5732                }
5733            }
5734            if (g_getfacl) {
5735                if (length_of_file(acl_fname) > 0) {
5736                    log_msg(1, "set_acl_list(%s,%s)",
5737                            biggies_whose_EXATs_we_should_set, acl_fname);
5738                    set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname);
5739                }
5740            }
5741        } else {
5742            iamhere
5743                ("No biggiefiles selected. So, no biggie-EXATs to set.");
5744        }
5745    }
5746    if (does_file_exist("/PAUSE")) {
5747        popup_and_OK
5748            ("Press ENTER to go on. Delete /PAUSE to stop these pauses.");
5749    }
5750
5751    close_progress_form();
5752    if (retval) {
5753        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
5754    } else {
5755        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
5756    }
5757    paranoid_free(biggies_whose_EXATs_we_should_set);
5758    paranoid_free(pathname_of_last_biggie_restored);
5759    paranoid_free(biggie_fname);
5760    paranoid_free(biggie_cksum);
5761    paranoid_free(xattr_fname);
5762    paranoid_free(acl_fname);
5763    paranoid_free(tmp);
5764    return (retval);
5765}
5766
5767/**************************************************************************
5768 *END_RESTORE_ALL_BIGGIEFILES_FROM_STREAM                                 *
5769 **************************************************************************/
5770
5771
5772
5773
5774
5775
5776/**
5777 * Restore all afioballs from the currently opened tape stream.
5778 * @param bkpinfo The backup information structure. Fields used:
5779 * - @c bkpinfo->backup_media_type
5780 * - @c bkpinfo->restore_path
5781 * @param filelist The node structure containing the list of files to be
5782 * restored. If no file in an afioball is in this list, afio will still be
5783 * called for that fileset, but nothing will be written.
5784 * @return 0 for success, or the number of filesets that failed.
5785 */
5786int
5787restore_all_tarballs_from_stream(struct s_node *filelist)
5788{
5789    int retval = 0;
5790    int res;
5791    long current_afioball_number = 0;
5792    int ctrl_chr;
5793    long max_val /*, total_noof_files */ ;
5794
5795  /** malloc **/
5796    char *tmp;
5797    char *progress_str;
5798    char *tmp_fname;
5799    char *xattr_fname;
5800    char *acl_fname;
5801
5802    long long tmp_size;
5803
5804    malloc_string(tmp);
5805    malloc_string(progress_str);
5806    malloc_string(tmp_fname);
5807    assert(bkpinfo != NULL);
5808    malloc_string(xattr_fname);
5809    malloc_string(acl_fname);
5810    mvaddstr_and_log_it(g_currentY, 0, "Restoring from archives");
5811    read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp);
5812    max_val = atol(tmp) + 1;
5813
5814    chdir(bkpinfo->restore_path);   /* I don't know why this is needed _here_ but it seems to be. -HR, 02/04/2002 */
5815
5816    run_program_and_log_output("pwd", 5);
5817
5818    sprintf(progress_str, "Restoring from media #%d",
5819            g_current_media_number);
5820    log_to_screen(progress_str);
5821    open_progress_form("Restoring from archives",
5822                       "Restoring data from the archives.",
5823                       "Please wait. This may take some time.",
5824                       progress_str, max_val);
5825
5826    log_msg(3, "hey");
5827
5828    res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
5829    if (res) {
5830        log_msg(2, "Warning - error reading afioball from tape");
5831    }
5832    retval += res;
5833    if (ctrl_chr != BLK_START_AFIOBALLS) {
5834        wrong_marker(BLK_START_AFIOBALLS, ctrl_chr);
5835    }
5836    log_msg(2, "ho");
5837    res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
5838    while (ctrl_chr != BLK_STOP_AFIOBALLS) {
5839        update_progress_form(progress_str);
5840        if (g_getfattr) {
5841            sprintf(xattr_fname, "%s/xattr-subset-%ld.tmp", bkpinfo->tmpdir,
5842                current_afioball_number);
5843            unlink(xattr_fname);
5844        }
5845        if (g_getfacl) {
5846            sprintf(acl_fname, "%s/acl-subset-%ld.tmp", bkpinfo->tmpdir,
5847                current_afioball_number);
5848            unlink(acl_fname);
5849        }
5850        if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
5851            iamhere("Reading EXAT files from tape");
5852            res =
5853                read_EXAT_files_from_tape(&tmp_size, tmp_fname,
5854                                          &ctrl_chr, xattr_fname,
5855                                          acl_fname);
5856        }
5857        if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
5858            wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
5859        }
5860        sprintf(tmp,
5861                "Restoring from fileset #%ld (name=%s, size=%ld K)",
5862                current_afioball_number, tmp_fname, (long) tmp_size >> 10);
5863        res =
5864            restore_a_tarball_from_stream(tmp_fname,
5865                                          current_afioball_number,
5866                                          filelist, tmp_size, xattr_fname,
5867                                          acl_fname);
5868        retval += res;
5869        if (res) {
5870            sprintf(tmp, "Fileset %ld - errors occurred",
5871                    current_afioball_number);
5872            log_to_screen(tmp);
5873        }
5874        res =
5875            read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
5876        if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
5877            wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
5878        }
5879
5880        current_afioball_number++;
5881        g_current_progress++;
5882        sprintf(progress_str, "Restoring from fileset #%ld on %s #%d",
5883                current_afioball_number,
5884                media_descriptor_string(bkpinfo->backup_media_type),
5885                g_current_media_number);
5886        res =
5887            read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr);
5888        if (g_getfattr) {
5889            unlink(xattr_fname);
5890        }
5891        if (g_getfacl) {
5892            unlink(acl_fname);
5893        }
5894    }                           // next
5895    log_msg(1, "All done with afioballs");
5896    close_progress_form();
5897    if (retval) {
5898        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
5899    } else {
5900        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
5901    }
5902    paranoid_free(tmp);
5903    paranoid_free(progress_str);
5904    paranoid_free(tmp_fname);
5905    paranoid_free(xattr_fname);
5906    paranoid_free(acl_fname);
5907    return (retval);
5908}
5909
5910/**************************************************************************
5911 *END_ RESTORE_ALL_TARBALLS_FROM_STREAM                                   *
5912 **************************************************************************/
5913
5914/* @} - end of LLrestoreGroup */
5915
5916
5917/**
5918 * Restore all files in @p filelist.
5919 * @param bkpinfo The backup information structure. Most fields are used.
5920 * @param filelist The node structure containing the list of files to be
5921 * restored.
5922 * @return 0 for success, or the number of afioballs and biggiefiles that failed.
5923 * @ingroup restoreGroup
5924 */
5925int restore_everything(struct s_node *filelist)
5926{
5927    int resA;
5928    int resB;
5929
5930  /** mallco ***/
5931    char *cwd;
5932    char *newpath;
5933    char *tmp;
5934    assert(bkpinfo != NULL);
5935
5936    malloc_string(cwd);
5937    malloc_string(newpath);
5938    malloc_string(tmp);
5939    log_msg(2, "restore_everything() --- starting");
5940    g_current_media_number = 1;
5941    getcwd(cwd, MAX_STR_LEN - 1);
5942    sprintf(tmp, "mkdir -p %s", bkpinfo->restore_path);
5943    run_program_and_log_output(tmp, FALSE);
5944    log_msg(1, "Changing dir to %s", bkpinfo->restore_path);
5945    chdir(bkpinfo->restore_path);
5946    getcwd(newpath, MAX_STR_LEN - 1);
5947    log_msg(1, "path is now %s", newpath);
5948    log_msg(1, "restoring everything");
5949    if (!find_home_of_exe("petris") && !g_text_mode) {
5950        newtDrawRootText(0, g_noof_rows - 2,
5951                         "Press ALT-<left cursor> twice to play Petris :-) ");
5952        newtRefresh();
5953    }
5954    mvaddstr_and_log_it(g_currentY, 0, "Preparing to read your archives");
5955    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
5956        mount_media();
5957        mvaddstr_and_log_it(g_currentY++, 0,
5958                            "Restoring OS and data from streaming media");
5959        if (bkpinfo->backup_media_type == cdstream) {
5960            openin_cdstream();
5961        } else {
5962            assert_string_is_neither_NULL_nor_zerolength(bkpinfo->media_device);
5963            openin_tape();
5964        }
5965        resA = restore_all_tarballs_from_stream(filelist);
5966        resB = restore_all_biggiefiles_from_stream(filelist);
5967        if (bkpinfo->backup_media_type == cdstream) {
5968            closein_cdstream();
5969        } else {
5970            closein_tape();
5971        }
5972    } else {
5973        mvaddstr_and_log_it(g_currentY++, 0,
5974                            "Restoring OS and data from CD/USB   ");
5975        mount_media();
5976        resA = restore_all_tarballs_from_CD(filelist);
5977        resB = restore_all_biggiefiles_from_CD(filelist);
5978    }
5979    chdir(cwd);
5980    if (resA + resB) {
5981        log_to_screen("Errors occurred while data was being restored.");
5982    }
5983    if (length_of_file("/etc/raidtab") > 0) {
5984        log_msg(2, "Copying local raidtab to restored filesystem");
5985        run_program_and_log_output("cp -f /etc/raidtab " MNT_RESTORING
5986                                   "/etc/raidtab", FALSE);
5987    }
5988    kill_petris();
5989    log_msg(2, "restore_everything() --- leaving");
5990    paranoid_free(cwd);
5991    paranoid_free(newpath);
5992    paranoid_free(tmp);
5993    return (resA + resB);
5994}
5995
5996/**************************************************************************
5997 *END_RESTORE_EVERYTHING                                                  *
5998 **************************************************************************/
5999
6000
6001
6002/**
6003 * @brief Haha. You wish! (This function is not implemented :-)
6004 */
6005int
6006restore_live_from_monitas_server(char *monitas_device,
6007                                 char *restore_this_directory,
6008                                 char *restore_here)
6009     /* NB: bkpinfo hasn't been populated yet, except for ->tmp which is "/tmp" */
6010{
6011    FILE *fout;
6012    int retval = 0;
6013    int i;
6014    int j;
6015    struct mountlist_itself the_mountlist;
6016    static struct raidlist_itself the_raidlist;
6017  /** malloc **/
6018    char tmp[MAX_STR_LEN + 1];
6019    char command[MAX_STR_LEN + 1];
6020    char datablock[256 * 1024];
6021    char datadisks_fname[MAX_STR_LEN + 1];
6022    long k;
6023    long length;
6024    long long llt;
6025    struct s_node *filelist = NULL;
6026    assert(bkpinfo != NULL);
6027    assert_string_is_neither_NULL_nor_zerolength(monitas_device);
6028    assert(restore_this_directory != NULL);
6029    assert(restore_here != NULL);
6030
6031    sprintf(tmp, "restore_here = '%s'", restore_here);
6032
6033    log_msg(2, tmp);
6034
6035    log_msg(2, "restore_live_from_monitas_server() - starting");
6036    unlink("/tmp/mountlist.txt");
6037    unlink("/tmp/filelist.full");
6038    unlink("/tmp/biggielist.txt");
6039    if (restore_here[0] == '\0') {
6040        strcpy(bkpinfo->restore_path, MNT_RESTORING);
6041    } else {
6042        strcpy(bkpinfo->restore_path, restore_here);
6043    }
6044    log_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI");
6045    sprintf(tmp, "FYI - data will be restored to %s",
6046            bkpinfo->restore_path);
6047    log_msg(3, tmp);
6048    log_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI");
6049    sprintf(datadisks_fname, "/tmp/mondorestore.datadisks.%d",
6050            (int) (random() % 32768));
6051    chdir(bkpinfo->tmpdir);
6052
6053    sprintf(command, "cat %s", monitas_device);
6054    g_tape_stream = popen(command, "r");    // for compatibility with openin_tape()
6055    if (!(fout = fopen(datadisks_fname, "w"))) {
6056        log_OS_error(datadisks_fname);
6057        return (1);
6058    }
6059    for (i = 0; i < 32; i++) {
6060        for (j = 0; j < 4; j++) {
6061            for (length = k = 0; length < 256 * 1024; length += k) {
6062                k = fread(datablock + length, 1, 256 * 1024 - length,
6063                          g_tape_stream);
6064            }
6065            fwrite(datablock, 1, length, fout);
6066            g_tape_posK += length;
6067        }
6068    }
6069    paranoid_fclose(fout);
6070    sprintf(command,
6071            "tar -zxvf %s ./tmp/mondo-restore.cfg ./tmp/mountlist.txt ./tmp/filelist.full ./tmp/biggielist.txt",
6072            datadisks_fname);
6073    run_program_and_log_output(command, 4);
6074    read_header_block_from_stream(&llt, tmp, &i);
6075    read_header_block_from_stream(&llt, tmp, &i);
6076
6077    unlink(datadisks_fname);
6078    read_cfg_file_into_bkpinfo(g_mondo_cfg_file);
6079    retval = load_mountlist(&the_mountlist, g_mountlist_fname); // in case read_cfg_file_into_bkpinfo   strcpy(bkpinfo->media_device, monitas_device);
6080
6081
6082    load_raidtab_into_raidlist(&the_raidlist, RAIDTAB_FNAME);
6083    iamhere("FIXME");
6084    fatal_error("This will fail");
6085    sprintf(command,
6086            "grep -E '^%s.*$' %s > %s",
6087            restore_this_directory, g_filelist_full, g_filelist_full);
6088    if (system(command)) {
6089        retval++;
6090        log_to_screen
6091            ("Error(s) occurred while processing filelist and wildcard");
6092    }
6093    iamhere("FIXME");
6094    fatal_error("This will fail");
6095    sprintf(command,
6096            "grep -E '^%s.*$' %s > %s",
6097            restore_this_directory, g_biggielist_txt, g_biggielist_txt);
6098    if (system(command)) {
6099        log_msg(1,
6100                "Error(s) occurred while processing biggielist and wildcard");
6101    }
6102    sprintf(command, "touch %s", g_biggielist_txt);
6103    run_program_and_log_output(command, FALSE);
6104//  filelist = load_filelist(g_filelist_restthese);  // FIXME --- this probably doesn't work because it doesn't include the biggiefiles
6105    retval += restore_everything(filelist);
6106    free_filelist(filelist);
6107    log_msg(2, "--------End of restore_live_from_monitas_server--------");
6108    return (retval);
6109}
6110
6111/**************************************************************************
6112 *END_RESTORE_LIVE_FROM_MONITAS_SERVER                                    *
6113 **************************************************************************/
6114
6115
6116
6117
6118extern void wait_until_software_raids_are_prepped(char *, int);
6119
6120
6121char which_restore_mode(void);
6122
6123
6124/**
6125 * Log a "don't panic" message to the logfile.
6126 */
6127void welcome_to_mondorestore()
6128{
6129    log_msg(0, "-------------- Mondo Restore v%s -------------", PACKAGE_VERSION);
6130    log_msg(0,
6131            "DON'T PANIC! Mondorestore logs almost everything, so please ");
6132    log_msg(0,
6133            "don't break out in a cold sweat just because you see a few  ");
6134    log_msg(0,
6135            "error messages in the log. Read them; analyze them; see if  ");
6136    log_msg(0,
6137            "they are significant; above all, verify your backups! Please");
6138    log_msg(0,
6139            "attach a compressed copy of this log to any e-mail you send ");
6140    log_msg(0,
6141            "to the Mondo mailing list when you are seeking technical    ");
6142    log_msg(0,
6143            "support. Without it, we can't help you.            - DevTeam");
6144    log_msg(0,
6145            "------------------------------------------------------------");
6146    log_msg(0,
6147            "BTW, despite (or perhaps because of) the wealth of messages,");
6148    log_msg(0,
6149            "some users are inclined to stop reading this log.  If Mondo ");
6150    log_msg(0,
6151            "stopped for some reason, chances are it's detailed here.    ");
6152    log_msg(0,
6153            "More than likely there's a message at the very end of this  ");
6154    log_msg(0,
6155            "log that will tell you what is wrong.  Please read it!      ");
6156    log_msg(0,
6157            "------------------------------------------------------------");
6158}
6159
6160
6161
6162/**
6163 * Restore the user's data.
6164 * What did you think it did, anyway? :-)
6165 */
6166int main(int argc, char *argv[])
6167{
6168    FILE *fin;
6169    FILE *fout;
6170    int retval = 0;
6171    int res;
6172//  int c;
6173    char *tmp;
6174
6175    struct mountlist_itself *mountlist;
6176    struct raidlist_itself *raidlist;
6177    struct s_node *filelist;
6178    char *a, *b;
6179    bool run_postnuke = FALSE;
6180
6181  /**************************************************************************
6182   * hugo-                                                                  *
6183   * busy stuff here - it needs some comments -stan                           *
6184   *                                                                        *
6185   **************************************************************************/
6186    if (getuid() != 0) {
6187        fprintf(stderr, "Please run as root.\r\n");
6188        exit(127);
6189    }
6190    if (!
6191        (bkpinfo = malloc(sizeof(struct s_bkpinfo)))) {
6192        fatal_error("Cannot malloc bkpinfo");
6193    }
6194    reset_bkpinfo();
6195
6196    g_loglevel = DEFAULT_MR_LOGLEVEL;
6197    malloc_string(</