/*************************************************************************** * restores mondoarchive data * $Id: mondorestore.c 1202 2007-02-25 09:59:33Z bruno $ ***************************************************************************/ /** * @file * The main file for mondorestore. */ /************************************************************************** * #include statements * **************************************************************************/ #include #include "my-stuff.h" #include "mr_mem.h" #include "mr_msg.h" #include "mr_str.h" #include "mondostructures.h" #include "libmondo.h" #include "mr-externs.h" #include "mondo-restore.h" #include "mondo-rstr-compare-EXT.h" #include "mondo-rstr-tools-EXT.h" extern void twenty_seconds_til_yikes(void); /* For use in other programs (ex. XMondo) */ #ifdef MONDORESTORE_MODULE #define main __mondorestore_main #define g_ISO_restore_mode __mondorestore_g_ISO_restore_mode #endif //static char cvsid[] = "$Id: mondorestore.c 1202 2007-02-25 09:59:33Z bruno $"; /************************************************************************** * Globals * **************************************************************************/ extern char *g_tmpfs_mountpt; // declared in libmondo-tools.c extern bool g_text_mode; extern FILE *g_fprep; extern double g_kernel_version; extern int g_partition_table_locked_up; extern int g_noof_rows; extern int partition_everything(struct mountlist_itself *mountlist); /** * @name Restore-Time Globals * @ingroup globalGroup * @{ */ /** * If TRUE, then SIGPIPE was just caught. * Set by the signal handler; cleared after it's handled. */ bool g_sigpipe_caught = FALSE; /** * If TRUE, then we're restoring from ISOs or an NFS server. * If FALSE, then we're restoring from some kind of real media (tape, CD, etc.) */ bool g_ISO_restore_mode = FALSE; /* are we in Iso Mode? */ /** * If TRUE, then we have had a successful "nuke" restore. */ bool g_I_have_just_nuked = FALSE; /** * The device to mount to get at the ISO images. Ignored unless @p g_ISO_restore_mode. */ char *g_isodir_device = NULL; /** * The format of @p g_isodir_device. Ignored unless @p g_ISO_restore_mode. */ char *g_isodir_format = NULL; /** * The location of 'biggielist.txt', containing the biggiefiles on the current archive set. */ char *g_biggielist_txt = NULL; /** * The location of 'filelist.full', containing all files (including biggiefiles) on * the current archive set. */ char *g_filelist_full = NULL; /** * The location of a file containing a list of the devices that were archived * as images, not as individual files. */ char *g_filelist_imagedevs = NULL; /** * The location of a file containing a list of imagedevs to actually restore. * @see g_filelist_imagedevs */ char *g_imagedevs_restthese = NULL; /** * The location of 'mondo-restore.cfg', containing the metadata * information for this backup. */ char *g_mondo_cfg_file = NULL; /** * The location of 'mountlist.txt', containing the information on the * user's partitions and hard drives. */ char *g_mountlist_fname = NULL; /** * Mondo's home directory during backup. Unused in mondo-restore; included * to avoid link errors. */ char *g_mondo_home = NULL; /* Busybox ps has no option and PID in first pos */ char *ps_options = ""; char *ps_proc_id = "$1"; extern char *g_getfacl; extern char *g_getfattr; /* @} - end of "Restore-Time Globals" in globalGroup */ extern int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived, char direction); /************************************************************************** * COMPAQ PROLIANT Stuff: needs some special help * **************************************************************************/ /** * The message to display if we detect that the user is using a Compaq Proliant. */ #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 CD/floppy in Interactive Mode.") /** * Allow the user to modify the mountlist before we partition & format their drives. * @param bkpinfo The backup information structure. @c disaster_recovery is the only field used. * @param mountlist The mountlist to let the user modify. * @param raidlist The raidlist that goes with @p mountlist. * @return 0 for success, nonzero for failure. * @ingroup restoreGuiGroup */ int let_user_edit_the_mountlist(struct s_bkpinfo *bkpinfo, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { int retval = 0, res = 0; mr_msg(2, "let_user_edit_the_mountlist() --- starting"); assert(bkpinfo != NULL); assert(mountlist != NULL); assert(raidlist != NULL); if (!bkpinfo->disaster_recovery) { strcpy(g_mountlist_fname, "/tmp/mountlist.txt"); mr_msg(2, "I guess you're testing edit_mountlist()"); } if (!does_file_exist(g_mountlist_fname)) { log_to_screen(g_mountlist_fname); log_to_screen(_("does not exist")); return (1); } retval = load_mountlist(mountlist, g_mountlist_fname); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); if (retval) { log_to_screen (_("Warning - load_raidtab_into_raidlist returned an error")); } res = edit_mountlist(g_mountlist_fname, mountlist, raidlist); if (res) { return (1); } save_mountlist_to_disk(mountlist, g_mountlist_fname); save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME); log_to_screen(_("I have finished editing the mountlist for you.")); return (retval); } /** * Determine whether @p mountlist contains a Compaq diagnostic partition. * @param mountlist The mountlist to examine. * @return TRUE if there's a Compaq diagnostic partition; FALSE if not. * @ingroup restoreUtilityGroup */ bool partition_table_contains_Compaq_diagnostic_partition(struct mountlist_itself * mountlist) { int i; assert(mountlist != NULL); for (i = 0; i < mountlist->entries; i++) { if (strstr(mountlist->el[i].format, "ompaq")) { mr_msg(2, "mountlist[%d] (%s) is %s (Compaq alert!)", i, mountlist->el[i].device, mountlist->el[i].format); return (TRUE); } } return (FALSE); } /************************************************************************** *END_PARTITION_TABLE_CONTAINS_COMPAQ_DIAGNOSTIC_PARTITION * **************************************************************************/ /** * Allow the user to abort the backup if we find that there is a Compaq diagnostic partition. * @note This function does not actually check for the presence of a Compaq partition. * @ingroup restoreUtilityGroup */ void offer_to_abort_because_Compaq_Proliants_suck(void) { popup_and_OK(COMPAQ_PROLIANTS_SUCK); if (ask_me_yes_or_no (_ ("Would you like to reboot and use your Compaq CD to prep your hard drive?"))) { fatal_error(_ ("Aborting. Please reboot and prep your hard drive with your Compaq CD.")); } } /************************************************************************** *END_OFFER_TO_ABORT_BECAUSE_COMPAQ_PROLIANTS_SUCK * **************************************************************************/ /** * Call interactive_mode(), nuke_mode(), or compare_mode() depending on the user's choice. * @param bkpinfo The backup information structure. Most fields are used. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist to go with @p mountlist. * @return The return code from the mode function called. * @ingroup restoreGroup */ int catchall_mode(struct s_bkpinfo *bkpinfo, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { char c, *tmp; int retval = 0; iamhere("inside catchall"); assert(bkpinfo != NULL); assert(mountlist != NULL); assert(raidlist != NULL); iamhere("pre wrm"); c = which_restore_mode(); iamhere("post wrm"); if (c == 'I' || c == 'N' || c == 'C') { interactively_obtain_media_parameters_from_user(bkpinfo, FALSE); } else { popup_and_OK(_ ("No restoring or comparing will take place today.")); if (is_this_device_mounted("/mnt/cdrom")) { run_program_and_log_output("umount /mnt/cdrom", FALSE); } if (g_ISO_restore_mode) { mr_asprintf(&tmp, "umount %s", bkpinfo->isodir); run_program_and_log_output(tmp, FALSE); mr_free(tmp); } paranoid_MR_finish(0); } iamhere("post int"); if (bkpinfo->backup_media_type == iso) { if (iso_fiddly_bits(bkpinfo, (c == 'N') ? TRUE : FALSE)) { mr_msg(2, "catchall_mode --- iso_fiddly_bits returned w/ error"); return (1); } else { mr_msg(2, "catchall_mode --- iso_fiddly_bits ok"); } } if (c == 'I') { mr_msg(2, "IM selected"); retval += interactive_mode(bkpinfo, mountlist, raidlist); } else if (c == 'N') { mr_msg(2, "NM selected"); retval += nuke_mode(bkpinfo, mountlist, raidlist); } else if (c == 'C') { mr_msg(2, "CM selected"); retval += compare_mode(bkpinfo, mountlist, raidlist); } return (retval); } /************************************************************************** *END_CATCHALL_MODE * **************************************************************************/ /************************************************************************** *END_ EXTRACT_CONFIG_FILE_FROM_RAMDISK * **************************************************************************/ /** * @addtogroup restoreGroup * @{ */ /** * Restore the user's data, in a disaster recovery situation, prompting the * user about whether or not to do every step. * The user can edit the mountlist, choose files to restore, etc. * @param bkpinfo The backup information structure. Most fields are used. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist to go with @p mountlist. * @return 0 for success, or the number of errors encountered. */ int interactive_mode(struct s_bkpinfo *bkpinfo, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { int retval = 0; int res; int ptn_errs = 0; int fmt_errs = 0; bool done; bool restore_all; char *tmp = NULL; char *tmp1 = NULL; char *fstab_fname = NULL; char *old_restpath = NULL; struct s_node *filelist = NULL; /* try to partition and format */ mr_msg(2, "interactive_mode --- starting (great, assertions OK)"); assert(bkpinfo != NULL); assert(mountlist != NULL); assert(raidlist != NULL); mr_msg(2, "interactive_mode --- assertions OK"); if (g_text_mode) { if (!ask_me_yes_or_no (_ ("Interactive Mode + textonly = experimental! Proceed anyway?"))) { fatal_error("Wise move."); } } iamhere("About to load config file"); get_cfg_file_from_archive_or_bust(bkpinfo); read_cfg_file_into_bkpinfo(g_mondo_cfg_file, bkpinfo); iamhere("Done loading config file; resizing ML"); #ifdef __FreeBSD__ if (strstr (call_program_and_get_last_line_of_output("cat /tmp/cmdline"), "noresize")) #else if (strstr (call_program_and_get_last_line_of_output("cat /proc/cmdline"), "noresize")) #endif { mr_msg(1, "Not resizing mountlist."); } else { resize_mountlist_proportionately_to_suit_new_drives(mountlist); } for (done = FALSE; !done;) { iamhere("About to edit mountlist"); if (g_text_mode) { save_mountlist_to_disk(mountlist, g_mountlist_fname); mr_asprintf(&tmp, "%s %s", find_my_editor(), g_mountlist_fname); res = system(tmp); mr_free(tmp); load_mountlist(mountlist, g_mountlist_fname); } else { res = edit_mountlist(g_mountlist_fname, mountlist, raidlist); } iamhere("Finished editing mountlist"); if (res) { paranoid_MR_finish(1); } mr_msg(2, "Proceeding..."); save_mountlist_to_disk(mountlist, g_mountlist_fname); save_raidlist_to_raidtab(raidlist, RAIDTAB_FNAME); mvaddstr_and_log_it(1, 30, _("Restoring Interactively")); if (bkpinfo->differential) { log_to_screen(_ ("Because this is a differential backup, disk")); log_to_screen(_ (" partitioning and formatting will not take place.")); done = TRUE; } else { if (ask_me_yes_or_no (_ ("Do you want to erase and partition your hard drives?"))) { if (partition_table_contains_Compaq_diagnostic_partition (mountlist)) { offer_to_abort_because_Compaq_Proliants_suck(); done = TRUE; } else { twenty_seconds_til_yikes(); g_fprep = fopen("/tmp/prep.sh", "w"); ptn_errs = partition_everything(mountlist); if (ptn_errs) { log_to_screen (_ ("Warning. Errors occurred during disk partitioning.")); } fmt_errs = format_everything(mountlist, FALSE, raidlist); if (!fmt_errs) { log_to_screen (_ ("Errors during disk partitioning were handled OK.")); log_to_screen(_ ("Partitions were formatted OK despite those errors.")); ptn_errs = 0; } if (!ptn_errs && !fmt_errs) { done = TRUE; } } paranoid_fclose(g_fprep); } else { mvaddstr_and_log_it(g_currentY++, 0, _ ("User opted not to partition the devices")); if (ask_me_yes_or_no (_("Do you want to format your hard drives?"))) { fmt_errs = format_everything(mountlist, TRUE, raidlist); if (!fmt_errs) { done = TRUE; } } else { ptn_errs = fmt_errs = 0; done = TRUE; } } if (fmt_errs) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Errors occurred. Please repartition and format drives manually.")); done = FALSE; } if (ptn_errs & !fmt_errs) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Errors occurred during partitioning. Formatting, however, went OK.")); done = TRUE; } if (!done) { if (!ask_me_yes_or_no(_("Re-edit the mountlist?"))) { retval++; iamhere("Leaving interactive_mode()"); return (retval); } } } } /* mount */ if (mount_all_devices(mountlist, TRUE)) { unmount_all_devices(mountlist); retval++; iamhere("Leaving interactive_mode()"); return (retval); } /* restore */ if ((restore_all = ask_me_yes_or_no(_ ("Do you want me to restore all of your data?")))) { mr_msg(1, "Restoring all data"); retval += restore_everything(bkpinfo, NULL); } else if ((restore_all = ask_me_yes_or_no (_("Do you want me to restore _some_ of your data?")))) { mr_asprintf(&old_restpath,bkpinfo->restore_path); for (done = FALSE; !done;) { unlink("/tmp/filelist.full"); filelist = process_filelist_and_biggielist(bkpinfo); /* Now you have /tmp/tmpfs/filelist.restore-these and /tmp/tmpfs/biggielist.restore-these; the former is a list of regular files; the latter, biggiefiles and imagedevs. */ if (filelist) { malloc_string(tmp1); gotos_suck: strcpy(tmp1, old_restpath); // (NB: MNT_RESTORING is where your filesystem is mounted now, by default) if (popup_and_get_string (_("Restore path"), _("Restore files to where?"), tmp1, MAX_STR_LEN / 4)) { if (!strcmp(tmp1, "/")) { if (!ask_me_yes_or_no(_("Are you sure?"))) { goto gotos_suck; } tmp1[0] = '\0'; // so we restore to [blank]/file/name :) } strcpy(bkpinfo->restore_path, tmp1); mr_msg(1, "Restoring subset"); retval += restore_everything(bkpinfo, filelist); free_filelist(filelist); } else { strcpy(bkpinfo->restore_path, old_restpath); free_filelist(filelist); } if (!ask_me_yes_or_no (_("Restore another subset of your backup?"))) { done = TRUE; } mr_free(tmp1); } else { done = TRUE; } } mr_free(old_restpath); } else { mvaddstr_and_log_it(g_currentY++, 0, _ ("User opted not to restore any data. ")); } if (retval) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Errors occurred during the restore phase. ")); } if (ask_me_yes_or_no(_("Initialize the boot loader?"))) { run_boot_loader(TRUE); } else { mvaddstr_and_log_it(g_currentY++, 0, _ ("User opted not to initialize the boot loader.")); } protect_against_braindead_sysadmins(); retval += unmount_all_devices(mountlist); /* if (restore_some || restore_all || */ if (ask_me_yes_or_no (_("Label your ext2 and ext3 partitions if necessary?"))) { mvaddstr_and_log_it(g_currentY, 0, _ ("Using e2label to label your ext2,3 partitions")); if (does_file_exist("/tmp/fstab.new")) { mr_asprintf(&fstab_fname, "/tmp/fstab.new"); } else { mr_asprintf(&fstab_fname, "/tmp/fstab"); } mr_asprintf(&tmp, "label-partitions-as-necessary %s < %s >> %s 2>> %s", g_mountlist_fname, fstab_fname, MONDO_LOGFILE, MONDO_LOGFILE); mr_free(fstab_fname); res = system(tmp); mr_free(tmp); if (res) { log_to_screen (_("label-partitions-as-necessary returned an error")); mvaddstr_and_log_it(g_currentY++, 74, _("Failed.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } retval += res; } iamhere("About to leave interactive_mode()"); if (retval) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Warning - errors occurred during the restore phase.")); } iamhere("Leaving interactive_mode()"); return(retval); } /************************************************************************** *END_INTERACTIVE_MODE * **************************************************************************/ /** * Run an arbitrary restore mode (prompt the user), but from ISO images * instead of real media. * @param bkpinfo The backup information structure. Most fields are used. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist that goes with @p mountlist. * @param nuke_me_please If TRUE, we plan to run Nuke Mode. * @return 0 for success, or the number of errors encountered. */ int iso_mode(struct s_bkpinfo *bkpinfo, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, bool nuke_me_please) { char c = ' '; int retval = 0; assert(bkpinfo != NULL); assert(mountlist != NULL); assert(raidlist != NULL); if (iso_fiddly_bits(bkpinfo, nuke_me_please)) { mr_msg(1, "iso_mode --- returning w/ error"); return (1); } else { c = which_restore_mode(); if (c == 'I' || c == 'N' || c == 'C') { interactively_obtain_media_parameters_from_user(bkpinfo, FALSE); } if (c == 'I') { retval += interactive_mode(bkpinfo, mountlist, raidlist); } else if (c == 'N') { retval += nuke_mode(bkpinfo, mountlist, raidlist); } else if (c == 'C') { retval += compare_mode(bkpinfo, mountlist, raidlist); } else { log_to_screen(_("OK, I shan't restore/compare any files.")); } } if (is_this_device_mounted(MNT_CDROM)) { paranoid_system("umount " MNT_CDROM); } if (system("umount /tmp/isodir 2> /dev/null")) { log_to_screen (_ ("WARNING - unable to unmount device where the ISO files are stored.")); } return (retval); } /************************************************************************** *END_ISO_MODE * **************************************************************************/ static void call_me_after_the_nuke(int retval) { char *tmp = NULL; char *tmp1 = NULL; if (retval) { log_to_screen(_("Errors occurred during the nuke phase.")); log_to_screen(_("Please visit our website at http://www.mondorescue.org for more information.")); } else { #ifdef __FreeBSD__ tmp1 = call_program_and_get_last_line_of_output("cat /tmp/cmdline"); #else tmp1 = call_program_and_get_last_line_of_output("cat /proc/cmdline"); #endif if ((strstr(tmp1,"restore") == NULL) || (strstr(tmp1,"RESTORE") == NULL)) { /* -H option */ mr_asprintf(&tmp, _ (" 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.")); popup_and_OK(tmp); mr_free(tmp); } log_to_screen(_ ("Mondo has restored your system. Please remove the backup media and reboot.")); log_to_screen(_ ("Thank you for using Mondo Rescue.")); log_to_screen(_ ("Please visit our website at http://www.mondorescue.org for more information.")); } g_I_have_just_nuked = TRUE; return; } /** * Restore the user's data automatically (no prompts), after a twenty-second * warning period. * @param bkpinfo The backup information structure. Most fields are used. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist that goes with @p mountlist. * @return 0 for success, or the number of errors encountered. * @warning THIS WILL ERASE ALL EXISTING DATA! */ int nuke_mode(struct s_bkpinfo *bkpinfo, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { int retval = 0; int res = 0; bool boot_loader_installed = FALSE; char *tmp = NULL; char tmpA[MAX_STR_LEN], tmpB[MAX_STR_LEN], tmpC[MAX_STR_LEN]; assert(bkpinfo != NULL); assert(mountlist != NULL); assert(raidlist != NULL); mr_msg(2, "nuke_mode --- starting"); get_cfg_file_from_archive_or_bust(bkpinfo); load_mountlist(mountlist, g_mountlist_fname); // in case read_cfg_file_into_bkpinfo updated the mountlist #ifdef __FreeBSD__ tmp = call_program_and_get_last_line_of_output("cat /tmp/cmdline"); #else tmp = call_program_and_get_last_line_of_output("cat /proc/cmdline"); #endif if (strstr(tmp,"noresize")) { mr_msg(2, "Not resizing mountlist."); } else { resize_mountlist_proportionately_to_suit_new_drives(mountlist); } if (!evaluate_mountlist(mountlist, tmpA, tmpB, tmpC)) { mr_asprintf(&tmp, _ ("Mountlist analyzed. Result: \"%s %s %s\" Switch to Interactive Mode?"), tmpA, tmpB, tmpC); if (ask_me_yes_or_no(tmp)) { mr_free(tmp); retval = interactive_mode(bkpinfo, mountlist, raidlist); call_me_after_the_nuke(retval); return(retval); } else { mr_free(tmp); fatal_error("Nuke Mode aborted. "); } } save_mountlist_to_disk(mountlist, g_mountlist_fname); mvaddstr_and_log_it(1, 30, _("Restoring Automatically")); if (bkpinfo->differential) { log_to_screen(_("Because this is a differential backup, disk")); log_to_screen(_ ("partitioning and formatting will not take place.")); res = 0; } else { if (partition_table_contains_Compaq_diagnostic_partition (mountlist)) { offer_to_abort_because_Compaq_Proliants_suck(); } else { twenty_seconds_til_yikes(); g_fprep = fopen("/tmp/prep.sh", "w"); #ifdef __FreeBSD__ tmp = call_program_and_get_last_line_of_output("cat /tmp/cmdline"); #else tmp = call_program_and_get_last_line_of_output("cat /proc/cmdline"); #endif if (strstr(tmp,"nopart")) { mr_msg(2, "Not partitioning drives due to 'nopart' option."); res = 0; } else { res = partition_everything(mountlist); if (res) { log_to_screen (_ ("Warning. Errors occurred during partitioning.")); res = 0; } } retval += res; if (!res) { log_to_screen(_("Preparing to format your disk(s)")); sleep(1); sync(); log_to_screen(_ ("Please wait. This may take a few minutes.")); res += format_everything(mountlist, FALSE, raidlist); } paranoid_fclose(g_fprep); } } retval += res; if (res) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Failed to partition and/or format your hard drives.")); if (ask_me_yes_or_no(_("Try in interactive mode instead?"))) { retval = interactive_mode(bkpinfo, mountlist, raidlist); call_me_after_the_nuke(retval); return(retval); } else if (!ask_me_yes_or_no (_("Would you like to try to proceed anyway?"))) { return(retval); } } retval = mount_all_devices(mountlist, TRUE); if (retval) { unmount_all_devices(mountlist); log_to_screen (_ ("Unable to mount all partitions. Sorry, I cannot proceed.")); return (retval); } iamhere("Restoring everything"); retval += restore_everything(bkpinfo, NULL); if (!run_boot_loader(FALSE)) { mr_msg(1, "Great! Boot loader was installed. No need for msg at end."); boot_loader_installed = TRUE; } protect_against_braindead_sysadmins(); retval += unmount_all_devices(mountlist); mvaddstr_and_log_it(g_currentY, 0, _ ("Using e2label to label your ext2,3 partitions")); mr_asprintf(&tmp, "label-partitions-as-necessary %s < /tmp/fstab", g_mountlist_fname); res = run_program_and_log_output(tmp, TRUE); mr_free(tmp); if (res) { log_to_screen(_ ("label-partitions-as-necessary returned an error")); mvaddstr_and_log_it(g_currentY++, 74, _("Failed.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } retval += res; call_me_after_the_nuke(retval); return (retval); } /************************************************************************** *END_NUKE_MODE * **************************************************************************/ /** * Restore the user's data (or a subset of it) to the live filesystem. * This should not be called if we're booted from CD! * @param bkpinfo The backup information structure. Most fields are used. * @return 0 for success, or the number of errors encountered. */ int restore_to_live_filesystem(struct s_bkpinfo *bkpinfo) { int retval = 0; char *old_restpath = NULL; struct mountlist_itself *mountlist = NULL; struct raidlist_itself *raidlist = NULL; struct s_node *filelist = NULL; mr_msg(1, "restore_to_live_filesystem() - starting"); assert(bkpinfo != NULL); mountlist = mr_malloc(sizeof(struct mountlist_itself)); raidlist = mr_malloc(sizeof(struct raidlist_itself)); strcpy(bkpinfo->restore_path, "/"); if (!g_restoring_live_from_cd) { popup_and_OK (_ ("Please insert tape/CD/boot floppy, then hit 'OK' to continue.")); sleep(1); } interactively_obtain_media_parameters_from_user(bkpinfo, FALSE); if (!bkpinfo->media_device[0]) { mr_msg(2, "Warning - failed to find media dev"); } else { mr_msg(2, "bkpinfo->media_device = %s", bkpinfo->media_device); } mr_msg(2, "bkpinfo->isodir = %s", bkpinfo->isodir); open_evalcall_form(_("Thinking...")); get_cfg_file_from_archive_or_bust(bkpinfo); read_cfg_file_into_bkpinfo(g_mondo_cfg_file, bkpinfo); load_mountlist(mountlist, g_mountlist_fname); // in case read_cfg_file_into_bkpinfo close_evalcall_form(); retval = load_mountlist(mountlist, g_mountlist_fname); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); filelist = process_filelist_and_biggielist(bkpinfo); if (filelist) { save_filelist(filelist, "/tmp/selected-files.txt"); mr_asprintf(&old_restpath,bkpinfo->restore_path); if (popup_and_get_string(_("Restore path"), _("Restore files to where? "), bkpinfo->restore_path)) { iamhere("Restoring everything"); retval += restore_everything(bkpinfo, filelist); } free_filelist(filelist); strcpy(bkpinfo->restore_path, old_restpath); mr_free(old_restpath); } if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) { mr_msg(2, "I probably don't need to unmount or eject the CD-ROM but I'm doing it anyway."); } run_program_and_log_output("umount " MNT_CDROM, FALSE); if ((!bkpinfo->please_dont_eject) && (bkpinfo->media_device != NULL)) { eject_device(bkpinfo->media_device); } mr_free(mountlist); mr_free(raidlist); return (retval); } /************************************************************************** *END_RESTORE_TO_LIVE_FILESYSTEM * **************************************************************************/ /* @} - end of restoreGroup */ #include /** * @addtogroup LLrestoreGroup * @{ */ /** * Restore biggiefile @p bigfileno from the currently mounted CD. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->backup_media_type * - @c bkpinfo->restore_path * @param bigfileno The biggiefile number (starting from 0) to restore. * @param filelist The node structure containing the list of files to restore. * If the biggiefile is not in this list, it will be skipped (return value will * still indicate success). * @return 0 for success (or skip), nonzero for failure. */ int restore_a_biggiefile_from_CD(struct s_bkpinfo *bkpinfo, long bigfileno, struct s_node *filelist, char *pathname_of_last_file_restored) { FILE *fin = NULL; FILE *fout = NULL; FILE *fbzip2 = NULL; char *checksum = NULL; char *outfile_fname = NULL; char *tmp = NULL; char *bzip2_command = NULL; char *suffix = NULL; char *bigblk = NULL; int retval = 0; int finished = FALSE; long sliceno = 0L; long siz; char *ntfsprog_fifo = NULL; char *file_to_openout = NULL; struct s_filename_and_lstat_info biggiestruct; struct utimbuf the_utime_buf, *ubuf = NULL; bool use_ntfsprog_hack = FALSE; pid_t pid; int res = 0; int old_loglevel; char *sz_msg = NULL; struct s_node *node = NULL; old_loglevel = g_loglevel; ubuf = &the_utime_buf; assert(bkpinfo != NULL); pathname_of_last_file_restored[0] = '\0'; bigblk = mr_malloc(TAPE_BLOCK_SIZE); if (!(fin = fopen(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""), "r"))) { log_to_screen("Cannot even open bigfile's info file"); return (1); } memset((void *) &biggiestruct, 0, sizeof(biggiestruct)); if (fread((void *) &biggiestruct, 1, sizeof(biggiestruct), fin) < sizeof(biggiestruct)) { mr_msg(2, "Warning - unable to get biggiestruct of bigfile #%d", bigfileno + 1); } paranoid_fclose(fin); mr_asprintf(&checksum, biggiestruct.checksum); if (!checksum[0]) { mr_msg(3, "Warning - bigfile %ld does not have a checksum", bigfileno + 1); } mr_free(checksum); if (!strncmp(biggiestruct.filename, "/dev/", 5)) // Whether NTFS or not :) { mr_asprintf(&outfile_fname, biggiestruct.filename); } else { mr_asprintf(&outfile_fname, "%s/%s", bkpinfo->restore_path, biggiestruct.filename); } /* skip file if we have a selective restore subset & it doesn't match */ if (filelist != NULL) { node = find_string_at_node(filelist, biggiestruct.filename); if (!node) { mr_msg(0, "Skipping %s (name isn't in filelist)", biggiestruct.filename); return (0); } else if (!(node->selected)) { mr_msg(1, "Skipping %s (name isn't in biggielist subset)", biggiestruct.filename); return (0); } } /* otherwise, continue */ mr_msg(1, "DEFINITELY restoring %s", biggiestruct.filename); if (biggiestruct.use_ntfsprog) { if (strncmp(biggiestruct.filename, "/dev/", 5)) { mr_msg(1, "I was in error when I set biggiestruct.use_ntfsprog to TRUE."); mr_msg(1, "%s isn't even in /dev", biggiestruct.filename); biggiestruct.use_ntfsprog = FALSE; } } if (biggiestruct.use_ntfsprog) // if it's an NTFS device { g_loglevel = 4; use_ntfsprog_hack = TRUE; mr_msg(2, "Calling ntfsclone in background because %s is an NTFS /dev entry", outfile_fname); mr_asprintf(&ntfsprog_fifo, "/tmp/%d.%d.000", (int) (random() % 32768), (int) (random() % 32768)); mkfifo(ntfsprog_fifo, 0x770); file_to_openout = ntfsprog_fifo; switch (pid = fork()) { case -1: fatal_error("Fork failure"); case 0: mr_msg(3, "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)", biggiestruct.filename, ntfsprog_fifo); res = feed_outfrom_ntfsprog(biggiestruct.filename, ntfsprog_fifo); exit(res); break; default: mr_msg(3, "feed_into_ntfsprog() called in background --- pid=%ld", (long int) (pid)); } } else { use_ntfsprog_hack = FALSE; file_to_openout = outfile_fname; if (!does_file_exist(outfile_fname)) // yes, it looks weird with the '!' but it's correct that way { make_hole_for_file(outfile_fname); } } mr_msg(2, "Reassembling big file %ld (%s)", bigfileno + 1, outfile_fname); /* last slice is zero-length and uncompressed; when we find it, we stop. We DON'T wait until there are no more slices; if we did that, We might stop at end of CD, not at last slice (which is 0-len and uncompd) */ strncpy(pathname_of_last_file_restored, biggiestruct.filename, MAX_STR_LEN - 1); pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0'; mr_msg(3, "file_to_openout = %s", file_to_openout); if (!(fout = fopen(file_to_openout, "w"))) { log_to_screen(_("Cannot openout file_to_openout - hard disk full?")); return (1); } mr_free(ntfsprog_fifo); mr_msg(3, "Opened out to %s", outfile_fname); // CD/DVD --> mondorestore --> ntfsclone --> hard disk itself for (sliceno = 1, finished = FALSE; !finished;) { if (!does_file_exist (slice_fname(bigfileno, sliceno, ARCHIVES_PATH, "")) && !does_file_exist(slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "lzo")) && !does_file_exist(slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "gz")) && !does_file_exist(slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) { mr_msg(3, "Cannot find a data slice or terminator slice on CD %d", g_current_media_number); g_current_media_number++; mr_msg(2, "Asking for %s #%d so that I may read slice #%ld\n", media_descriptor_string(bkpinfo->backup_media_type), g_current_media_number, sliceno); log_to_screen(_("Restoring from %s #%d"), bkpinfo->backup_media_string, g_current_media_number); insist_on_this_cd_number(bkpinfo, g_current_media_number); log_to_screen(_("Continuing to restore.")); } else { mr_asprintf(&tmp, slice_fname(bigfileno, sliceno, ARCHIVES_PATH, "")); if (does_file_exist(tmp) && length_of_file(tmp) == 0) { mr_msg(2, "End of bigfile # %ld (slice %ld is the terminator)", bigfileno + 1, sliceno); finished = TRUE; mr_free(tmp); continue; } else { mr_free(tmp); if (does_file_exist (slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "lzo"))) { mr_asprintf(&bzip2_command, "lzop"); mr_asprintf(&suffix, "lzo"); } else if (does_file_exist (slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "gz"))) { mr_asprintf(&bzip2_command, "gzip"); mr_asprintf(&suffix, "gz"); } else if (does_file_exist (slice_fname (bigfileno, sliceno, ARCHIVES_PATH, "bz2"))) { mr_asprintf(&bzip2_command, "bzip2"); mr_asprintf(&suffix, "bz2"); } else if (does_file_exist (slice_fname (bigfileno, sliceno, ARCHIVES_PATH, ""))) { mr_asprintf(&bzip2_command, ""); mr_asprintf(&suffix, ""); } else { log_to_screen(_("OK, that's pretty fsck0red...")); return (1); } } if (bzip2_command[0] != '\0') { mr_strcat(bzip2_command, " -dc %s 2>> %s", slice_fname(bigfileno, sliceno, ARCHIVES_PATH, suffix), MONDO_LOGFILE); } else { mr_free(bzip2_command); mr_asprintf(&bzip2_command, "cat %s 2>> %s", slice_fname(bigfileno, sliceno, ARCHIVES_PATH, suffix), MONDO_LOGFILE); } mr_asprintf(&tmp, "Working on %s #%d, file #%ld, slice #%ld", bkpinfo->backup_media_string, g_current_media_number, bigfileno + 1, sliceno); mr_msg(2, tmp); if (!g_text_mode) { newtDrawRootText(0, g_noof_rows - 2, tmp); newtRefresh(); update_progress_form(tmp); } mr_free(tmp); if (!(fbzip2 = popen(bzip2_command, "r"))) { mr_free(bzip2_command); mr_free(suffix); fatal_error("Can't run popen command"); } mr_free(bzip2_command); mr_free(suffix); while (!feof(fbzip2)) { siz = fread(bigblk, 1, TAPE_BLOCK_SIZE, fbzip2); if (siz > 0) { siz = fwrite(bigblk, 1, siz, fout); } } paranoid_pclose(fbzip2); sliceno++; g_current_progress++; } } paranoid_fclose(fout); g_loglevel = old_loglevel; if (use_ntfsprog_hack) { mr_msg(3, "Waiting for ntfsclone to finish"); mr_asprintf(&tmp, " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null"); while (system(tmp) == 0) { sleep(1); } mr_free(tmp); log_it("OK, ntfsclone has really finished"); } if (strcmp(outfile_fname, "/dev/null")) { chown(outfile_fname, biggiestruct.properties.st_uid, biggiestruct.properties.st_gid); chmod(outfile_fname, biggiestruct.properties.st_mode); ubuf->actime = biggiestruct.properties.st_atime; ubuf->modtime = biggiestruct.properties.st_mtime; utime(outfile_fname, ubuf); } mr_free(outfile_fname); mr_free(bigblk); return (retval); } /************************************************************************** *END_ RESTORE_A_BIGGIEFILE_FROM_CD * **************************************************************************/ /** * Restore a biggiefile from the currently opened stream. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->restore_path * - @c bkpinfo->zip_exe * @param orig_bf_fname The original filename of the biggiefile. * @param biggiefile_number The number of the biggiefile (starting from 0). * @param filelist The node structure containing the list of files to be restored. * If @p orig_bf_fname is not in the list, it will be ignored. * @return 0 for success (or skip), nonzero for failure. */ int restore_a_biggiefile_from_stream(struct s_bkpinfo *bkpinfo, char *orig_bf_fname, long biggiefile_number, char *orig_checksum, //UNUSED long long biggiefile_size, //UNUSED struct s_node *filelist, int use_ntfsprog, char *pathname_of_last_file_restored) { FILE *pout = NULL; FILE *fin = NULL; /** mallocs ********/ char *tmp = NULL; char *tmp1 = NULL; char *command = NULL; char *outfile_fname = NULL; char *ntfsprog_fifo = NULL; char *file_to_openout = NULL; struct s_node *node = NULL; int old_loglevel = 0; long current_slice_number = 0; int retval = 0; int res = 0; int ctrl_chr = '\0'; long long slice_siz = 0L; bool dummy_restore = FALSE; bool use_ntfsprog_hack = FALSE; pid_t pid; struct s_filename_and_lstat_info biggiestruct; struct utimbuf the_utime_buf, *ubuf = NULL; ubuf = &the_utime_buf; old_loglevel = g_loglevel; assert(bkpinfo != NULL); assert(orig_bf_fname != NULL); assert(orig_checksum != NULL); pathname_of_last_file_restored[0] = '\0'; if (use_ntfsprog == BLK_START_A_PIHBIGGIE) { use_ntfsprog = 1; mr_msg(1, "%s --- pih=YES", orig_bf_fname); } else if (use_ntfsprog == BLK_START_A_NORMBIGGIE) { use_ntfsprog = 0; mr_msg(1, "%s --- pih=NO", orig_bf_fname); } else { use_ntfsprog = 0; mr_msg(1, "%s --- pih=NO (weird marker though)", orig_bf_fname); } strncpy(pathname_of_last_file_restored, orig_bf_fname, MAX_STR_LEN - 1); pathname_of_last_file_restored[MAX_STR_LEN - 1] = '\0'; /* open out to biggiefile to be restored (or /dev/null if biggiefile is not to be restored) */ if (filelist != NULL) { node = find_string_at_node(filelist, orig_bf_fname); if (!node) { dummy_restore = TRUE; mr_msg(1, "Skipping big file %ld (%s) - not in biggielist subset", biggiefile_number + 1, orig_bf_fname); pathname_of_last_file_restored[0] = '\0'; } else if (!(node->selected)) { dummy_restore = TRUE; mr_msg(1, "Skipping %s (name isn't in biggielist subset)", orig_bf_fname); pathname_of_last_file_restored[0] = '\0'; } } if (use_ntfsprog) { if (strncmp(orig_bf_fname, "/dev/", 5)) { mr_msg(1, "I was in error when I set use_ntfsprog to TRUE."); mr_msg(1, "%s isn't even in /dev", orig_bf_fname); use_ntfsprog = FALSE; } } if (use_ntfsprog) { g_loglevel = 4; mr_asprintf(&outfile_fname, orig_bf_fname); use_ntfsprog_hack = TRUE; mr_msg(2, "Calling ntfsclone in background because %s is a /dev entry", outfile_fname); mr_asprintf(&ntfsprog_fifo, "%s/%d.%d.000", bkpinfo->tmpdir, (int) (random() % 32768), (int) (random() % 32768)); mkfifo(ntfsprog_fifo, 0x770); file_to_openout = ntfsprog_fifo; switch (pid = fork()) { case -1: fatal_error("Fork failure"); case 0: mr_msg(3, "CHILD - fip - calling feed_outfrom_ntfsprog(%s, %s)", outfile_fname, ntfsprog_fifo); res = feed_outfrom_ntfsprog(outfile_fname, ntfsprog_fifo); exit(res); break; default: mr_msg(3, "feed_into_ntfsprog() called in background --- pid=%ld", (long int) (pid)); } } else { if (!strncmp(orig_bf_fname, "/dev/", 5)) // non-NTFS partition { mr_asprintf(&outfile_fname, orig_bf_fname); } else // biggiefile { mr_asprintf(&outfile_fname, "%s/%s", bkpinfo->restore_path, orig_bf_fname); } use_ntfsprog_hack = FALSE; file_to_openout = outfile_fname; if (!does_file_exist(outfile_fname)) // yes, it looks weird with the '!' but it's correct that way { make_hole_for_file(outfile_fname); } mr_msg(2, "Reassembling big file %ld (%s)", biggiefile_number + 1, orig_bf_fname); } if (dummy_restore) { mr_free(outfile_fname); mr_asprintf(&outfile_fname, "/dev/null"); } if (!bkpinfo->zip_exe[0]) { mr_asprintf(&command, "cat > \"%s\"", file_to_openout); } else { mr_asprintf(&command, "%s -dc > \"%s\" 2>> %s", bkpinfo->zip_exe, file_to_openout, MONDO_LOGFILE); } mr_msg(3, "Pipe command = '%s'", command); mr_free(outfile_fname); mr_free(ntfsprog_fifo); /* restore biggiefile, one slice at a time */ if (!(pout = popen(command, "w"))) { fatal_error("Cannot pipe out"); } mr_free(command); malloc_string(tmp1); for (res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr); ctrl_chr != BLK_STOP_A_BIGGIE; res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr)) { if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) { wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr); } mr_asprintf(&tmp, "Working on file #%ld, slice #%ld ", biggiefile_number + 1, current_slice_number); mr_msg(2, tmp); if (!g_text_mode) { newtDrawRootText(0, g_noof_rows - 2, tmp); newtRefresh(); } mr_strip_spaces(tmp); update_progress_form(tmp); mr_free(tmp); if (current_slice_number == 0) { res = read_file_from_stream_to_file(bkpinfo, "/tmp/biggie-blah.txt", slice_siz); if (!(fin = fopen("/tmp/biggie-blah.txt", "r"))) { log_OS_error("blah blah"); } else { if (fread ((void *) &biggiestruct, 1, sizeof(biggiestruct), fin) < sizeof(biggiestruct)) { mr_msg(2, "Warning - unable to get biggiestruct of bigfile #%d", biggiefile_number + 1); } paranoid_fclose(fin); } } else { res = read_file_from_stream_to_stream(bkpinfo, pout, slice_siz); } retval += res; res = read_header_block_from_stream(&slice_siz, tmp1, &ctrl_chr); if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) { wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr); } current_slice_number++; g_current_progress++; } mr_free(tmp1); paranoid_pclose(pout); mr_msg(1, "pathname_of_last_file_restored is now %s", pathname_of_last_file_restored); if (use_ntfsprog_hack) { mr_msg(3, "Waiting for ntfsclone to finish"); mr_asprintf(&tmp, " ps | grep \" ntfsclone \" | grep -v grep > /dev/null 2> /dev/null"); while (system(tmp) == 0) { sleep(1); } mr_free(tmp); mr_msg(3, "OK, ntfsclone has really finished"); } mr_msg(3, "biggiestruct.filename = %s", biggiestruct.filename); mr_msg(3, "biggiestruct.checksum = %s", biggiestruct.checksum); if (strcmp(outfile_fname, "/dev/null")) { chmod(outfile_fname, biggiestruct.properties.st_mode); chown(outfile_fname, biggiestruct.properties.st_uid, biggiestruct.properties.st_gid); ubuf->actime = biggiestruct.properties.st_atime; ubuf->modtime = biggiestruct.properties.st_mtime; utime(outfile_fname, ubuf); } g_loglevel = old_loglevel; return (retval); } /************************************************************************** *END_RESTORE_A_BIGGIEFILE_FROM_STREAM * **************************************************************************/ /** * Restore @p tarball_fname from CD. * @param tarball_fname The filename of the tarball to restore (in /mnt/cdrom). * This will be used unmodified. * @param current_tarball_number The number (starting from 0) of the fileset * we're restoring now. * @param filelist The node structure containing the list of files to be * restored. If no file in the afioball is in this list, afio will still be * called, but nothing will be written. * @return 0 for success, nonzero for failure. */ int restore_a_tarball_from_CD(char *tarball_fname, long current_tarball_number, struct s_node *filelist, struct s_bkpinfo *bkpinfo) { int retval = 0; int res = 0; char *p = NULL; /** malloc **/ char *command = NULL; char *tmp = NULL; char *filelist_name = NULL; char *filelist_subset_fname = NULL; char *executable = NULL; char *temp_log = NULL; long matches = 0; bool use_star = FALSE; char *xattr_fname = NULL; char *acl_fname = NULL; assert_string_is_neither_NULL_nor_zerolength(tarball_fname); mr_msg(5, "Entering"); use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE; mr_asprintf(&command, "mkdir -p %s/tmp", MNT_RESTORING); run_program_and_log_output(command, 9); mr_free(command); mr_asprintf(&filelist_name, MNT_CDROM "/archives/filelist.%ld", current_tarball_number); if (length_of_file(filelist_name) <= 2) { mr_msg(2, "There are _zero_ files in filelist '%s'", filelist_name); mr_msg(2, "This is a bit silly (ask dev-team to fix mondo_makefilelist, please)"); mr_msg(2, "but it's non-critical. It's cosmetic. Don't worry about it."); retval = 0; mr_msg(5, "Leaving"); mr_free(filelist_name); return (retval); } if (count_lines_in_file(filelist_name) <= 0 || length_of_file(tarball_fname) <= 0) { mr_msg(3, "length_of_file(%s) = %llu", tarball_fname, length_of_file(tarball_fname)); log_to_screen(_("Unable to restore fileset #%ld (CD I/O error)"), current_tarball_number); retval = 1; mr_msg(5, "Leaving"); mr_free(filelist_name); return (retval); } if (filelist) { mr_asprintf(&filelist_subset_fname, "/tmp/filelist-subset-%ld.tmp", current_tarball_number); if ((matches = save_filelist_entries_in_common(filelist_name, filelist, filelist_subset_fname, use_star)) <= 0) { mr_msg(1, "Skipping fileset %ld", current_tarball_number); } else { mr_msg(3, "Saved fileset %ld's subset to %s", current_tarball_number, filelist_subset_fname); } log_to_screen("Tarball #%ld --- %ld matches", current_tarball_number, matches); } mr_free(filelist_name); if (filelist == NULL || matches > 0) { if (g_getfattr) { mr_asprintf(&xattr_fname, XATTR_LIST_FNAME_RAW_SZ, MNT_CDROM "/archives", current_tarball_number); } if (g_getfacl) { mr_asprintf(&acl_fname, ACL_LIST_FNAME_RAW_SZ, MNT_CDROM "/archives", current_tarball_number); } if (strstr(tarball_fname, ".bz2")) { mr_asprintf(&executable, "-P bzip2 -Z"); } else if (strstr(tarball_fname, ".gz")) { mr_asprintf(&executable, "-P gzip -Z"); } else if (strstr(tarball_fname, ".lzo")) { mr_asprintf(&executable, "-P lzop -Z"); } if (executable == NULL) { mr_asprintf(&tmp, "which %s > /dev/null 2> /dev/null", executable); if (run_program_and_log_output(tmp, FALSE)) { log_to_screen (_ ("(compare_a_tarball) Compression program not found - oh no!")); mr_free(tmp); mr_free(executable); mr_free(acl_fname); mr_free(xattr_fname); mr_free(filelist_subset_fname); paranoid_MR_finish(1); } mr_free(tmp); } #ifdef __FreeBSD__ #define BUFSIZE 512 #else #define BUFSIZE (1024L*1024L)/TAPE_BLOCK_SIZE #endif if (use_star) { mr_sprintf(&command, "star -x -force-remove -U " STAR_ACL_SZ " errctl= file=%s", tarball_fname); if (strstr(tarball_fname, ".bz2")) { mr_strcat(command, " -bz"); } } else { if (filelist_subset_fname != NULL) { mr_asprintf(&command, "afio -i -M 8m -b %ld -c %ld %s -w '%s' %s", TAPE_BLOCK_SIZE, BUFSIZE, executable, filelist_subset_fname, tarball_fname); } else { mr_asprintf(&command, "afio -i -b %ld -c %ld -M 8m %s %s", TAPE_BLOCK_SIZE, BUFSIZE, executable, tarball_fname); } } mr_free(executable); #undef BUFSIZE mr_asprintf(&temp_log, "/tmp/%d.%d", (int) (random() % 32768), (int) (random() % 32768)); mr_strcat(command, " 2>> %s >> %s", temp_log, temp_log); mr_msg(1, "command = '%s'", command); unlink(temp_log); res = system(command); if (res) { p = strstr(command, "-acl "); if (p) { p[0] = p[1] = p[2] = p[3] = ' '; mr_msg(1, "new command = '%s'", command); res = system(command); } } mr_free(command); if (res && length_of_file(temp_log) < 5) { res = 0; } if (g_getfattr) { mr_msg(1, "Setting fattr list %s", xattr_fname); if (length_of_file(xattr_fname) > 0) { res = set_fattr_list(filelist_subset_fname, xattr_fname); if (res) { log_to_screen ("Errors occurred while setting extended attributes"); } else { mr_msg(1, "I set xattr OK"); } retval += res; } } if (g_getfacl) { mr_msg(1, "Setting acl list %s", acl_fname); if (length_of_file(acl_fname) > 0) { res = set_acl_list(filelist_subset_fname, acl_fname); if (res) { log_to_screen ("Errors occurred while setting access control lists"); } else { mr_msg(1, "I set ACL OK"); } retval += res; } } if (retval) { mr_asprintf(&command, "cat %s >> %s", temp_log, MONDO_LOGFILE); system(command); mr_free(command); mr_msg(2, "Errors occurred while processing fileset #%d", current_tarball_number); } else { mr_msg(2, "Fileset #%d processed OK", current_tarball_number); } unlink(xattr_fname); mr_free(xattr_fname); unlink(acl_fname); mr_free(acl_fname); unlink(temp_log); mr_free(temp_log); } if (does_file_exist("/PAUSE")) { popup_and_OK (_ ("Press ENTER to go on. Delete /PAUSE to stop these pauses.")); } unlink(filelist_subset_fname); mr_free(filelist_subset_fname); mr_msg(5, "Leaving"); return (retval); } /************************************************************************** *END_RESTORE_A_TARBALL_FROM_CD * **************************************************************************/ /** * Restore a tarball from the currently opened stream. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->backup_media_type * - @c bkpinfo->media_device * - @c bkpinfo->zip_exe * @param tarball_fname The filename of the afioball to restore. * @param current_tarball_number The number (starting from 0) of the fileset * we're restoring now. * @param filelist The node structure containing the list of files to be * restored. If no file in the afioball is in this list, afio will still be * called, but nothing will be written. * @param size The size (in @b bytes) of the afioball. * @return 0 for success, nonzero for failure. */ int restore_a_tarball_from_stream(struct s_bkpinfo *bkpinfo, char *tarball_fname, long current_tarball_number, struct s_node *filelist, long long size, char *xattr_fname, char *acl_fname) { int retval = 0; int res = 0; /** malloc add ***/ char *tmp = NULL; char *command = NULL; char *afio_fname = NULL; char *filelist_fname = NULL; char *filelist_subset_fname = NULL; char *executable = NULL; long matches = 0; bool restore_this_fileset = FALSE; bool use_star = FALSE; assert(bkpinfo != NULL); assert_string_is_neither_NULL_nor_zerolength(tarball_fname); /* to do it with a file... */ use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE; mr_msg(2, "Restoring from fileset #%ld (%ld KB) on %s #%d", current_tarball_number, (long) size >> 10, bkpinfo->backup_media_string, g_current_media_number); run_program_and_log_output("mkdir -p " MNT_RESTORING "/tmp", FALSE); /**************************************************************************** * Use RAMDISK's /tmp; saves time; oh wait, it's too small * * Well, pipe from tape to afio, then; oh wait, can't do that either: bug * * in afio or someting; oh darn.. OK, use tmpfs :-) * ****************************************************************************/ mr_asprintf(&afio_fname, "/tmp/tmpfs/archive.tmp.%ld", current_tarball_number); mr_asprintf(&filelist_fname, "%s/filelist.%ld", bkpinfo->tmpdir, current_tarball_number); mr_asprintf(&filelist_subset_fname, "%s/filelist-subset-%ld.tmp", bkpinfo->tmpdir, current_tarball_number); res = read_file_from_stream_to_file(bkpinfo, afio_fname, size); if (strstr(tarball_fname, ".star")) { bkpinfo->use_star = TRUE; } if (res) { mr_msg(1, "Warning - error reading afioball from tape"); } if (bkpinfo->compression_level != 0) { if (bkpinfo->use_star) { mr_asprintf(&executable, " -bz"); } else { mr_asprintf(&executable, "-P %s -Z", bkpinfo->zip_exe); } } if (!filelist) // if unconditional restore then restore entire fileset { restore_this_fileset = TRUE; } else // If restoring selectively then get TOC from tarball { if (strstr(tarball_fname, ".star.")) { use_star = TRUE; mr_asprintf(&command, "star -t file=%s %s", afio_fname, executable); } else { use_star = FALSE; mr_asprintf(&command, "afio -t -M 8m -b %ld %s %s", TAPE_BLOCK_SIZE, executable, afio_fname); } mr_strcat(command, " > %s 2>> %s", filelist_fname, MONDO_LOGFILE); mr_msg(1, "command = %s", command); if (system(command)) { mr_msg(4, "Warning - error occurred while retrieving TOC"); } mr_free(command); if ((matches = save_filelist_entries_in_common(filelist_fname, filelist, filelist_subset_fname, use_star)) <= 0 || length_of_file(filelist_subset_fname) < 2) { if (length_of_file(filelist_subset_fname) < 2) { mr_msg(1, "No matches found in fileset %ld", current_tarball_number); } mr_msg(2, "Skipping fileset %ld", current_tarball_number); restore_this_fileset = FALSE; } else { mr_msg(5, "%ld matches. Saved fileset %ld's subset to %s", matches, current_tarball_number, filelist_subset_fname); restore_this_fileset = TRUE; } } unlink(filelist_fname); mr_free(filelist_fname); // Concoct the call to star/afio to restore files if (strstr(tarball_fname, ".star.")) { // star if (filelist) { mr_asprintf(&command, "star -x file=%s %s list=%s 2>> %s", afio_fname, executable, filelist_subset_fname, MONDO_LOGFILE); } else { mr_asprintf(&command, "star -x file=%s %s 2>> %s", afio_fname, executable, MONDO_LOGFILE); } } else { // afio if (filelist) { mr_asprintf(&command, "afio -i -M 8m -b %ld %s -w %s %s 2>> %s", TAPE_BLOCK_SIZE, executable, filelist_subset_fname, afio_fname, MONDO_LOGFILE); } else { mr_asprintf(&command, "afio -i -M 8m -b %ld %s %s 2>> %s", TAPE_BLOCK_SIZE, executable, afio_fname, MONDO_LOGFILE); } } mr_free(executable); // Call if IF there are files to restore (selectively/unconditionally) if (restore_this_fileset) { mr_msg(1, "Calling command='%s'", command); paranoid_system(command); if (g_getfattr) { iamhere("Restoring xattr stuff"); res = set_fattr_list(filelist_subset_fname, xattr_fname); if (res) { mr_msg(1, "Errors occurred while setting xattr"); } else { mr_msg(1, "I set xattr OK"); } retval += res; } if (g_getfacl) { iamhere("Restoring acl stuff"); res = set_acl_list(filelist_subset_fname, acl_fname); if (res) { mr_msg(1, "Errors occurred while setting ACL"); } else { mr_msg(1, "I set ACL OK"); } retval += res; } } else { mr_msg(1, "NOT CALLING '%s'", command); } mr_free(command); if (does_file_exist("/PAUSE") && current_tarball_number >= 50) { log_to_screen(_("Paused after set %ld"), current_tarball_number); popup_and_OK(_("Pausing. Press ENTER to continue.")); } unlink(filelist_subset_fname); unlink(afio_fname); mr_free(filelist_subset_fname); mr_free(afio_fname); return (retval); } /************************************************************************** *END_RESTORE_A_TARBALL_FROM_STREAM * **************************************************************************/ /** * Restore all biggiefiles from all media in this CD backup. * The CD with the last afioball should be currently mounted. * @param bkpinfo The backup information structure. @c backup_media_type is the * only field used in this function. * @param filelist The node structure containing the list of files to be * restored. If a prospective biggiefile is not in this list, it will be ignored. * @return 0 for success, nonzero for failure. */ int restore_all_biggiefiles_from_CD(struct s_bkpinfo *bkpinfo, struct s_node *filelist) { int retval = 0; int res = 0; long noof_biggiefiles = 0L, bigfileno = 0L, total_slices = 0L; char *tmp = NULL; char *tmp1 = NULL; bool just_changed_cds = FALSE, finished = FALSE; char *xattr_fname = NULL; char *acl_fname = NULL; char *biggies_whose_EXATs_we_should_set = NULL; // EXtended ATtributes char *pathname_of_last_biggie_restored = NULL; FILE *fbw = NULL; malloc_string(tmp1); malloc_string(pathname_of_last_biggie_restored); assert(bkpinfo != NULL); mr_asprintf(&biggies_whose_EXATs_we_should_set, "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir); if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) { mr_msg(1, "Warning - cannot openout %s", biggies_whose_EXATs_we_should_set); } read_cfg_var(g_mondo_cfg_file, "total-slices", tmp1); total_slices = atol(tmp1); mr_free(tmp1); mr_asprintf(&tmp, _("Reassembling large files ")); mvaddstr_and_log_it(g_currentY, 0, tmp); mr_free(tmp); if (length_of_file(BIGGIELIST) < 6) { mr_msg(1, "OK, no biggielist; not restoring biggiefiles"); return (0); } noof_biggiefiles = count_lines_in_file(BIGGIELIST); if (noof_biggiefiles <= 0) { mr_msg(2, "OK, no biggiefiles in biggielist; not restoring biggiefiles"); return (0); } mr_msg(2, "OK, there are %ld biggiefiles in the archives", noof_biggiefiles); open_progress_form(_("Reassembling large files"), _("I am now reassembling all the large files."), _("Please wait. This may take some time."), "", total_slices); for (bigfileno = 0, finished = FALSE; !finished;) { mr_msg(2, "Thinking about restoring bigfile %ld", bigfileno + 1); if (!does_file_exist(slice_fname(bigfileno, 0, ARCHIVES_PATH, ""))) { mr_msg(3, "...but its first slice isn't on this CD. Perhaps this was a selective restore?"); mr_msg(3, "Cannot find bigfile #%ld 's first slice on %s #%d", bigfileno + 1, bkpinfo->backup_media_string, g_current_media_number); mr_msg(3, "Slicename would have been %s", slice_fname(bigfileno + 1, 0, ARCHIVES_PATH, "")); // I'm not positive 'just_changed_cds' is even necessary... if (just_changed_cds) { just_changed_cds = FALSE; mr_msg(3, "I'll continue to scan this CD for bigfiles to be restored."); } else if (does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST")) { insist_on_this_cd_number(bkpinfo, ++g_current_media_number); log_to_screen(_("Restoring from %s #%d"), bkpinfo->backup_media_string, g_current_media_number); just_changed_cds = TRUE; } else { mr_msg(2, "There was no bigfile #%ld. That's OK.", bigfileno + 1); mr_msg(2, "I'm going to stop restoring bigfiles now."); finished = TRUE; } } else { just_changed_cds = FALSE; mr_asprintf(&tmp, _("Restoring big file %ld"), bigfileno + 1); update_progress_form(tmp); mr_free(tmp); res = restore_a_biggiefile_from_CD(bkpinfo, bigfileno, filelist, pathname_of_last_biggie_restored); iamhere(pathname_of_last_biggie_restored); if (fbw && pathname_of_last_biggie_restored[0]) { fprintf(fbw, "%s\n", pathname_of_last_biggie_restored); } retval += res; bigfileno++; } } if (fbw) { fclose(fbw); if (g_getfattr) { mr_asprintf(&xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH); if (length_of_file(xattr_fname) > 0) { set_fattr_list(biggies_whose_EXATs_we_should_set, xattr_fname); } } if (g_getfacl) { mr_asprintf(&acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, ARCHIVES_PATH); if (length_of_file(acl_fname) > 0) { set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname); } } mr_free(acl_fname); mr_free(xattr_fname); } mr_free(biggies_whose_EXATs_we_should_set); if (does_file_exist("/PAUSE")) { popup_and_OK (_ ("Press ENTER to go on. Delete /PAUSE to stop these pauses.")); } close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, _("Errors.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } mr_free(pathname_of_last_biggie_restored); return (retval); } /************************************************************************** *END_RESTORE_ALL_BIGGIFILES_FROM_CD * **************************************************************************/ /** * Restore all afioballs from all CDs in the backup. * The first CD should be inserted (if not, it will be asked for). * @param bkpinfo The backup information structure. @c backup_media_type is the * only field used in @e this function. * @param filelist The node structure containing the list of files to be * restored. If no file in some particular afioball is in this list, afio will * still be called for that fileset, but nothing will be written. * @return 0 for success, or the number of filesets that failed. */ int restore_all_tarballs_from_CD(struct s_bkpinfo *bkpinfo, struct s_node *filelist) { int retval = 0; int res = 0; int attempts = 0; long current_tarball_number = 0; long max_val = 0L; /**malloc ***/ char *tmp = NULL; char *tmp1 = NULL; char *tarball_fname = NULL; char *progress_str = NULL; char *comment = NULL; malloc_string(tmp1); malloc_string(tarball_fname); malloc_string(progress_str); malloc_string(comment); assert(bkpinfo != NULL); mvaddstr_and_log_it(g_currentY, 0, _("Restoring from archives")); mr_msg(2, "Insisting on 1st CD, so that I can have a look at LAST-FILELIST-NUMBER"); if (g_current_media_number != 1) { mr_msg(3, "OK, that's jacked up."); g_current_media_number = 1; } insist_on_this_cd_number(bkpinfo, g_current_media_number); read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp1); max_val = atol(tmp1) + 1; mr_free(tmp1); mr_asprintf(&progress_str, _("Restoring from %s #%d"), bkpinfo->backup_media_string, g_current_media_number); log_to_screen(progress_str); open_progress_form(_("Restoring from archives"), _("Restoring data from the archives."), _("Please wait. This may take some time."), progress_str, max_val); for (;;) { insist_on_this_cd_number(bkpinfo, g_current_media_number); update_progress_form(progress_str); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.bz2", current_tarball_number); if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.lzo", current_tarball_number); } if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.gz", current_tarball_number); } if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.afio.", current_tarball_number); } if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.star.bz2", current_tarball_number); } if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); mr_asprintf(&tarball_fname, MNT_CDROM "/archives/%ld.star.", current_tarball_number); } if (!does_file_exist(tarball_fname)) { mr_free(tarball_fname); if (current_tarball_number == 0) { log_to_screen (_ ("No tarballs. Strange. Maybe you only backed up freakin' big files?")); mr_free(progress_str); return (0); } if (!does_file_exist(MNT_CDROM "/archives/NOT-THE-LAST") || system("find " MNT_CDROM "/archives/slice* > /dev/null 2> /dev/null") == 0) { mr_free(tarball_fname); mr_free(progress_str); break; } g_current_media_number++; mr_free(progress_str); mr_asprintf(&progress_str, _("Restoring from %s #%d"), bkpinfo->backup_media_string, g_current_media_number); log_to_screen(progress_str); } else { mr_free(progress_str); mr_asprintf(&progress_str, _("Restoring from fileset #%ld on %s #%d"), current_tarball_number, bkpinfo->backup_media_string, g_current_media_number); for (res = 999, attempts = 0; attempts < 3 && res != 0; attempts++) { res = restore_a_tarball_from_CD(tarball_fname, current_tarball_number, filelist, bkpinfo); } mr_asprintf(&tmp, _("%s #%d, fileset #%ld - restore "), media_descriptor_string(bkpinfo->backup_media_type), g_current_media_number, current_tarball_number); if (res) { mr_strcat(tmp, _("reported errors")); } else { mr_strcat(tmp, _("succeeded")); } if (attempts > 1) { mr_strcat(tmp, _(" (%d attempts) - review logs"), attempts); } if (attempts > 1) { log_to_screen(tmp); } mr_free(tmp); retval += res; current_tarball_number++; g_current_progress++; } mr_free(tarball_fname); } mr_free(progress_str); close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, _("Errors.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } return (retval); } /************************************************************************** *END_RESTORE_ALL_TARBALLS_FROM_CD * **************************************************************************/ /** * Restore all biggiefiles from the currently opened stream. * @param bkpinfo The backup information structure. Passed to other functions. * @param filelist The node structure containing the list of files to be * restored. If a prospective biggiefile is not in the list, it will be ignored. * @return 0 for success, or the number of biggiefiles that failed. */ int restore_all_biggiefiles_from_stream(struct s_bkpinfo *bkpinfo, struct s_node *filelist) { long noof_biggiefiles = 0L; long current_bigfile_number = 0L; long total_slices = 0L; int retval = 0; int res = 0; int ctrl_chr = 0; /** malloc add ****/ char *tmp = NULL; char *biggie_fname = NULL; char *biggie_cksum = NULL; char *xattr_fname = NULL; char *acl_fname = NULL; char *pathname_of_last_biggie_restored = NULL; char *biggies_whose_EXATs_we_should_set = NULL; // EXtended ATtributes long long biggie_size = (long long)0; FILE *fbw; assert(bkpinfo != NULL); malloc_string(tmp); malloc_string(biggie_fname); malloc_string(biggie_cksum); malloc_string(pathname_of_last_biggie_restored); read_cfg_var(g_mondo_cfg_file, "total-slices", tmp); total_slices = atol(tmp); mr_free(tmp); mr_asprintf(&tmp, "Reassembling large files "); if (g_getfattr) { mr_asprintf(&xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir); } if (g_getfacl) { mr_asprintf(&acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir); } mvaddstr_and_log_it(g_currentY, 0, tmp); mr_free(tmp); mr_asprintf(&biggies_whose_EXATs_we_should_set, "%s/biggies-whose-EXATs-we-should-set", bkpinfo->tmpdir); if (!(fbw = fopen(biggies_whose_EXATs_we_should_set, "w"))) { mr_msg(1, "Warning - cannot openout %s", biggies_whose_EXATs_we_should_set); } // get xattr and acl files if they're there res = read_header_block_from_stream(&biggie_size, biggie_fname, &ctrl_chr); if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) { res = read_EXAT_files_from_tape(bkpinfo, &biggie_size, biggie_fname, &ctrl_chr, xattr_fname, acl_fname); } noof_biggiefiles = atol(biggie_fname); mr_msg(2, "OK, there are %ld biggiefiles in the archives", noof_biggiefiles); open_progress_form(_("Reassembling large files"), _("I am now reassembling all the large files."), _("Please wait. This may take some time."), "", total_slices); for (res = read_header_block_from_stream(&biggie_size, biggie_fname, &ctrl_chr); ctrl_chr != BLK_STOP_BIGGIEFILES; res = read_header_block_from_stream(&biggie_size, biggie_fname, &ctrl_chr)) { if (ctrl_chr != BLK_START_A_NORMBIGGIE && ctrl_chr != BLK_START_A_PIHBIGGIE) { wrong_marker(BLK_START_A_NORMBIGGIE, ctrl_chr); } /* BERLIOS: useless p = strrchr(biggie_fname, '/'); if (!p) { p = biggie_fname; } else { p++; } */ mr_asprintf(&tmp, _("Restoring big file %ld (%lld K)"), current_bigfile_number + 1, biggie_size / 1024); update_progress_form(tmp); mr_free(tmp); res = restore_a_biggiefile_from_stream(bkpinfo, biggie_fname, current_bigfile_number, biggie_cksum, biggie_size, filelist, ctrl_chr, pathname_of_last_biggie_restored); mr_msg(1, "I believe I have restored %s", pathname_of_last_biggie_restored); if (fbw && pathname_of_last_biggie_restored[0]) { fprintf(fbw, "%s\n", pathname_of_last_biggie_restored); } mr_free(pathname_of_last_biggie_restored); retval += res; current_bigfile_number++; } if (current_bigfile_number != noof_biggiefiles && noof_biggiefiles != 0) { mr_msg(1, "Warning - bigfileno=%ld but noof_biggiefiles=%ld\n", current_bigfile_number, noof_biggiefiles); } else { mr_msg(1, "%ld biggiefiles in biggielist.txt; %ld biggiefiles processed today.", noof_biggiefiles, current_bigfile_number); } if (fbw) { fclose(fbw); if (length_of_file(biggies_whose_EXATs_we_should_set) > 2) { iamhere("Setting biggie-EXATs"); if (g_getfattr) { if (length_of_file(xattr_fname) > 0) { mr_msg(1, "set_fattr_List(%s,%s)", biggies_whose_EXATs_we_should_set, xattr_fname); set_fattr_list(biggies_whose_EXATs_we_should_set, xattr_fname); } } if (g_getfacl) { if (length_of_file(acl_fname) > 0) { mr_msg(1, "set_acl_list(%s,%s)", biggies_whose_EXATs_we_should_set, acl_fname); set_acl_list(biggies_whose_EXATs_we_should_set, acl_fname); } } } else { iamhere ("No biggiefiles selected. So, no biggie-EXATs to set."); } } mr_free(xattr_fname); mr_free(acl_fname); mr_free(biggies_whose_EXATs_we_should_set); if (does_file_exist("/PAUSE")) { popup_and_OK (_ ("Press ENTER to go on. Delete /PAUSE to stop these pauses.")); } close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, _("Errors.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } mr_free(biggie_fname); mr_free(biggie_cksum); return (retval); } /************************************************************************** *END_RESTORE_ALL_BIGGIEFILES_FROM_STREAM * **************************************************************************/ /** * Restore all afioballs from the currently opened tape stream. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->backup_media_type * - @c bkpinfo->restore_path * @param filelist The node structure containing the list of files to be * restored. If no file in an afioball is in this list, afio will still be * called for that fileset, but nothing will be written. * @return 0 for success, or the number of filesets that failed. */ int restore_all_tarballs_from_stream(struct s_bkpinfo *bkpinfo, struct s_node *filelist) { int retval = 0; int res = 0; long current_afioball_number = 0; int ctrl_chr = 0; long max_val = 0L /*, total_noof_files */ ; /** malloc **/ char *tmp = NULL; char *progress_str = NULL; char *tmp_fname = NULL; char *xattr_fname = NULL; char *acl_fname = NULL; long long tmp_size = 0L; malloc_string(tmp_fname); malloc_string(tmp); assert(bkpinfo != NULL); mvaddstr_and_log_it(g_currentY, 0, _("Restoring from archives")); read_cfg_var(g_mondo_cfg_file, "last-filelist-number", tmp); max_val = atol(tmp) + 1; mr_free(tmp); chdir(bkpinfo->restore_path); /* I don't know why this is needed _here_ but it seems to be. -HR, 02/04/2002 */ run_program_and_log_output("pwd", 5); mr_asprintf(&progress_str, _("Restoring from media #%d"), g_current_media_number); log_to_screen(progress_str); open_progress_form(_("Restoring from archives"), _("Restoring data from the archives."), _("Please wait. This may take some time."), progress_str, max_val); mr_msg(3, "hey"); res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr); if (res) { mr_msg(2, "Warning - error reading afioball from tape"); } retval += res; if (ctrl_chr != BLK_START_AFIOBALLS) { wrong_marker(BLK_START_AFIOBALLS, ctrl_chr); } mr_msg(2, "ho"); res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr); while (ctrl_chr != BLK_STOP_AFIOBALLS) { update_progress_form(progress_str); if (g_getfattr) { mr_asprintf(&xattr_fname, "%s/xattr-subset-%ld.tmp", bkpinfo->tmpdir, current_afioball_number); unlink(xattr_fname); } if (g_getfacl) { mr_asprintf(&acl_fname, "%s/acl-subset-%ld.tmp", bkpinfo->tmpdir, current_afioball_number); unlink(acl_fname); } if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) { iamhere("Reading EXAT files from tape"); res = read_EXAT_files_from_tape(bkpinfo, &tmp_size, tmp_fname, &ctrl_chr, xattr_fname, acl_fname); } if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) { wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr); } /* BERLIOS: useless ? mr_asprintf(&tmp, _("Restoring from fileset #%ld (name=%s, size=%ld K)"), current_afioball_number, tmp_fname, (long) tmp_size >> 10); */ res = restore_a_tarball_from_stream(bkpinfo, tmp_fname, current_afioball_number, filelist, tmp_size, xattr_fname, acl_fname); retval += res; if (res) { log_to_screen("Fileset %ld - errors occurred", current_afioball_number); } res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr); if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) { wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr); } current_afioball_number++; g_current_progress++; mr_free(progress_str); mr_asprintf(&progress_str, _("Restoring from fileset #%ld on %s #%d"), current_afioball_number, bkpinfo->backup_media_string, g_current_media_number); res = read_header_block_from_stream(&tmp_size, tmp_fname, &ctrl_chr); if (g_getfattr) { unlink(xattr_fname); } if (g_getfacl) { unlink(acl_fname); } mr_free(xattr_fname); mr_free(acl_fname); } // next mr_free(progress_str); mr_free(tmp_fname); mr_msg(1, "All done with afioballs"); close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, _("Errors.")); } else { mvaddstr_and_log_it(g_currentY++, 74, _("Done.")); } return (retval); } /************************************************************************** *END_ RESTORE_ALL_TARBALLS_FROM_STREAM * **************************************************************************/ /* @} - end of LLrestoreGroup */ /** * Restore all files in @p filelist. * @param bkpinfo The backup information structure. Most fields are used. * @param filelist The node structure containing the list of files to be * restored. * @return 0 for success, or the number of afioballs and biggiefiles that failed. * @ingroup restoreGroup */ int restore_everything(struct s_bkpinfo *bkpinfo, struct s_node *filelist) { int resA; int resB; /** mallco ***/ char *cwd = NULL; char *newpath = NULL; char *tmp = NULL; assert(bkpinfo != NULL); malloc_string(cwd); malloc_string(newpath); mr_msg(2, "restore_everything() --- starting"); g_current_media_number = 1; /* BERLIOS: should test return value, or better change the function */ getcwd(cwd, MAX_STR_LEN - 1); mr_asprintf(&tmp, "mkdir -p %s", bkpinfo->restore_path); run_program_and_log_output(tmp, FALSE); mr_free(tmp); mr_msg(1, "Changing dir to %s", bkpinfo->restore_path); chdir(bkpinfo->restore_path); /* BERLIOS: should test return value, or better change the function */ getcwd(newpath, MAX_STR_LEN - 1); mr_msg(1, "path is now %s", newpath); mr_msg(1, "restoring everything"); if (!find_home_of_exe("petris") && !g_text_mode) { newtDrawRootText(0, g_noof_rows - 2, _ ("Press ALT- twice to play Petris :-) ")); newtRefresh(); } mvaddstr_and_log_it(g_currentY, 0, _("Preparing to read your archives")); if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) { mount_cdrom(bkpinfo); mvaddstr_and_log_it(g_currentY++, 0, _ ("Restoring OS and data from streaming media")); if (bkpinfo->backup_media_type == cdstream) { openin_cdstream(bkpinfo); } else { assert_string_is_neither_NULL_nor_zerolength(bkpinfo-> media_device); openin_tape(bkpinfo); } resA = restore_all_tarballs_from_stream(bkpinfo, filelist); resB = restore_all_biggiefiles_from_stream(bkpinfo, filelist); if (bkpinfo->backup_media_type == cdstream) { closein_cdstream(bkpinfo); } else { closein_tape(bkpinfo); } } else { mvaddstr_and_log_it(g_currentY++, 0, _("Restoring OS and data from CD ")); mount_cdrom(bkpinfo); resA = restore_all_tarballs_from_CD(bkpinfo, filelist); resB = restore_all_biggiefiles_from_CD(bkpinfo, filelist); } chdir(cwd); if (resA + resB) { log_to_screen(_("Errors occurred while data was being restored.")); } if (length_of_file("/etc/raidtab") > 0) { mr_msg(2, "Copying local raidtab to restored filesystem"); run_program_and_log_output("cp -f /etc/raidtab " MNT_RESTORING "/etc/raidtab", FALSE); } kill_petris(); mr_msg(2, "restore_everything() --- leaving"); mr_free(cwd); mr_free(newpath); return (resA + resB); } /************************************************************************** *END_RESTORE_EVERYTHING * **************************************************************************/ /** * @brief Haha. You wish! (This function is not implemented :-) */ int restore_live_from_monitas_server(struct s_bkpinfo *bkpinfo, char *monitas_device, char *restore_this_directory, char *restore_here) /* NB: bkpinfo hasn't been populated yet, except for ->tmp which is "/tmp" */ { FILE *fout; int retval = 0; int i; int j; struct mountlist_itself the_mountlist; static struct raidlist_itself the_raidlist; /** malloc **/ char tmp[MAX_STR_LEN + 1]; char command[MAX_STR_LEN + 1]; char datablock[256 * 1024]; char datadisks_fname[MAX_STR_LEN + 1]; long k; long length; long long llt; struct s_node *filelist = NULL; assert(bkpinfo != NULL); assert_string_is_neither_NULL_nor_zerolength(monitas_device); assert(restore_this_directory != NULL); assert(restore_here != NULL); sprintf(tmp, "restore_here = '%s'", restore_here); mr_msg(2, tmp); mr_msg(2, "restore_live_from_monitas_server() - starting"); unlink("/tmp/mountlist.txt"); unlink("/tmp/filelist.full"); unlink("/tmp/biggielist.txt"); if (restore_here[0] == '\0') { strcpy(bkpinfo->restore_path, MNT_RESTORING); } else { strcpy(bkpinfo->restore_path, restore_here); } mr_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI"); sprintf(tmp, "FYI - data will be restored to %s", bkpinfo->restore_path); mr_msg(3, tmp); mr_msg(3, "FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI FYI"); sprintf(datadisks_fname, "/tmp/mondorestore.datadisks.%d", (int) (random() % 32768)); chdir(bkpinfo->tmpdir); sprintf(command, "cat %s", monitas_device); g_tape_stream = popen(command, "r"); // for compatibility with openin_tape() if (!(fout = fopen(datadisks_fname, "w"))) { log_OS_error(datadisks_fname); return (1); } for (i = 0; i < 32; i++) { for (j = 0; j < 4; j++) { for (length = k = 0; length < 256 * 1024; length += k) { k = fread(datablock + length, 1, 256 * 1024 - length, g_tape_stream); } fwrite(datablock, 1, length, fout); g_tape_posK += length; } } paranoid_fclose(fout); sprintf(command, "tar -zxvf %s tmp/mondo-restore.cfg tmp/mountlist.txt tmp/filelist.full tmp/biggielist.txt", datadisks_fname); run_program_and_log_output(command, 4); read_header_block_from_stream(&llt, tmp, &i); read_header_block_from_stream(&llt, tmp, &i); unlink(datadisks_fname); read_cfg_file_into_bkpinfo(g_mondo_cfg_file, bkpinfo); retval = load_mountlist(&the_mountlist, g_mountlist_fname); // in case read_cfg_file_into_bkpinfo strcpy(bkpinfo->media_device, monitas_device); load_raidtab_into_raidlist(&the_raidlist, RAIDTAB_FNAME); iamhere("FIXME"); fatal_error("This will fail"); sprintf(command, "grep -E '^%s.*$' %s > %s", restore_this_directory, g_filelist_full, g_filelist_full); if (system(command)) { retval++; log_to_screen ("Error(s) occurred while processing filelist and wildcard"); } iamhere("FIXME"); fatal_error("This will fail"); sprintf(command, "grep -E '^%s.*$' %s > %s", restore_this_directory, g_biggielist_txt, g_biggielist_txt); if (system(command)) { mr_msg(1, "Error(s) occurred while processing biggielist and wildcard"); } sprintf(command, "touch %s", g_biggielist_txt); run_program_and_log_output(command, FALSE); // filelist = load_filelist(g_filelist_restthese); // FIXME --- this probably doesn't work because it doesn't include the biggiefiles retval += restore_everything(bkpinfo, filelist); free_filelist(filelist); mr_msg(2, "--------End of restore_live_from_monitas_server--------"); return (retval); } /************************************************************************** *END_RESTORE_LIVE_FROM_MONITAS_SERVER * **************************************************************************/ extern void wait_until_software_raids_are_prepped(char *, int); char which_restore_mode(void); /** * Log a "don't panic" message to the logfile. */ void welcome_to_mondorestore() { mr_msg(0, "-------------- Mondo Restore v%s -------------", PACKAGE_VERSION); mr_msg(0, "DON'T PANIC! Mondorestore logs almost everything, so please "); mr_msg(0, "don't break out in a cold sweat just because you see a few "); mr_msg(0, "error messages in the log. Read them; analyze them; see if "); mr_msg(0, "they are significant; above all, verify your backups! Please"); mr_msg(0, "attach a compressed copy of this log to any e-mail you send "); mr_msg(0, "to the Mondo mailing list when you are seeking technical "); mr_msg(0, "support. Without it, we can't help you. - DevTeam"); mr_msg(0, "------------------------------------------------------------"); mr_msg(0, "BTW, despite (or perhaps because of) the wealth of messages,"); mr_msg(0, "some users are inclined to stop reading this log. If Mondo "); mr_msg(0, "stopped for some reason, chances are it's detailed here. "); mr_msg(0, "More than likely there's a message near the end of this "); mr_msg(0, "log that will tell you what is wrong. Please read it! "); mr_msg(0, "------------------------------------------------------------"); } /** * Restore the user's data. * What did you think it did, anyway? :-) */ int main(int argc, char *argv[]) { FILE *fin = NULL; FILE *fout = NULL; int retval = 0; int res = 0; char *tmp = NULL; struct mountlist_itself *mountlist = NULL; struct raidlist_itself *raidlist = NULL; struct s_bkpinfo *bkpinfo = NULL; struct s_node *filelist = NULL; char *a = NULL, *b = NULL; bool run_postnuke = FALSE; #ifdef ENABLE_NLS setlocale(LC_ALL, ""); (void) textdomain("mondo"); #endif if (getuid() != 0) { fprintf(stderr, _("Please run as root.\n")); exit(127); } g_loglevel = DEFAULT_MR_LOGLEVEL; /* Configure global variables */ #ifdef __FreeBSD__ if (strstr (call_program_and_get_last_line_of_output("cat /tmp/cmdline"), "textonly")) #else if (strstr (call_program_and_get_last_line_of_output("cat /proc/cmdline"), "textonly")) #endif { g_text_mode = TRUE; mr_msg(1, "TEXTONLY MODE"); } else { g_text_mode = FALSE; } // newt :-) bkpinfo = mr_malloc(sizeof(struct s_bkpinfo)); mountlist = mr_malloc(sizeof(struct mountlist_itself)); raidlist = mr_malloc(sizeof(struct raidlist_itself)); malloc_libmondo_global_strings(); strcpy(g_mondo_home, call_program_and_get_last_line_of_output("which mondorestore")); sprintf(g_tmpfs_mountpt, "/tmp/tmpfs"); make_hole_for_dir(g_tmpfs_mountpt); g_current_media_number = 1; // precaution run_program_and_log_output("mkdir -p " MNT_CDROM, FALSE); run_program_and_log_output("mkdir -p /mnt/floppy", FALSE); malloc_string(a); malloc_string(b); setup_MR_global_filenames(bkpinfo); // malloc() and set globals, using bkpinfo->tmpdir etc. reset_bkpinfo(bkpinfo); bkpinfo->backup_media_type = none; // in case boot disk was made for one backup type but user wants to restore from another backup type bkpinfo->backup_media_string = NULL; bkpinfo->restore_data = TRUE; // Well, yeah :-) if (am_I_in_disaster_recovery_mode()) { run_program_and_log_output("mount / -o remount,rw", 2); } // for b0rken distros g_main_pid = getpid(); srandom((int) (time(NULL))); register_pid(getpid(), "mondo"); set_signals(TRUE); g_kernel_version = get_kernel_version(); mr_msg(1, "FYI - g_mountlist_fname = %s", g_mountlist_fname); if (strlen(g_mountlist_fname) < 3) { fatal_error ("Serious error in malloc()'ing. Could be a bug in your glibc."); } mkdir(MNT_CDROM, 0x770); /* Backup original mountlist.txt */ mr_asprintf(&tmp, "%s.orig", g_mountlist_fname); if (!does_file_exist(g_mountlist_fname)) { mr_msg(2, "%ld: Warning - g_mountlist_fname (%s) does not exist yet", __LINE__, g_mountlist_fname); } else if (!does_file_exist(tmp)) { mr_free(tmp); mr_asprintf(&tmp, "cp -f %s %s.orig", g_mountlist_fname, g_mountlist_fname); run_program_and_log_output(tmp, FALSE); } mr_free(tmp); /* Init directories */ make_hole_for_dir(bkpinfo->tmpdir); mr_asprintf(&tmp, "mkdir -p %s", bkpinfo->tmpdir); run_program_and_log_output(tmp, FALSE); mr_free(tmp); make_hole_for_dir("/var/log"); make_hole_for_dir("/tmp/tmpfs"); /* just in case... */ run_program_and_log_output("umount " MNT_CDROM, FALSE); run_program_and_log_output ("ln -sf /var/log/mondo-archive.log /tmp/mondo-restore.log", FALSE); run_program_and_log_output("rm -Rf /tmp/tmpfs/mondo.tmp.*", FALSE); /* Init GUI */ malloc_libmondo_global_strings(); setup_newt_stuff(); /* call newtInit and setup screen log */ welcome_to_mondorestore(); if (bkpinfo->disaster_recovery) { mr_msg(1, "I am in disaster recovery mode"); } else { mr_msg(1, "I am in normal, live mode"); } iamhere("what time is it"); /* Process command-line parameters */ if (argc == 2 && strcmp(argv[1], "--edit-mountlist") == 0) { #ifdef __FreeBSD__ system("mv -f /tmp/raidconf.txt /etc/raidtab"); if (!does_file_exist("/etc/raidtab")) system("vinum printconfig > /etc/raidtab"); #endif load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); if (!does_file_exist(g_mountlist_fname)) { strcpy(g_mountlist_fname, "/tmp/mountlist.txt"); } res = let_user_edit_the_mountlist(bkpinfo, mountlist, raidlist); #ifdef __FreeBSD__ system("mv -f /etc/raidtab /tmp/raidconf.txt"); #endif paranoid_MR_finish(res); } g_loglevel = DEFAULT_MR_LOGLEVEL; if (argc == 3 && strcmp(argv[1], "--echo-to-screen") == 0) { fout = fopen("/tmp/out.txt", "w"); fput_string_one_char_at_a_time(stderr, argv[2]); finish(0); } if (argc == 3 && strcmp(argv[1], "--gendf") == 0) { make_grub_install_scriptlet(argv[2]); finish(0); } if (argc >= 2 && strcmp(argv[1], "--pih") == 0) { if (system("mount | grep cdrom 2> /dev/null > /dev/null")) { system("mount " MNT_CDROM); } bkpinfo->compression_level = 1; g_current_media_number = 2; strcpy(bkpinfo->restore_path, "/tmp/TESTING"); bkpinfo->backup_media_type = dvd; open_progress_form(_("Reassembling /dev/hda1"), _("Shark is a bit of a silly person."), _("Please wait. This may take some time."), "", 1999); system("rm -Rf /tmp/*pih*"); malloc_string(tmp); restore_a_biggiefile_from_CD(bkpinfo, 42, NULL, tmp); mr_free(tmp); } if (argc == 5 && strcmp(argv[1], "--common") == 0) { g_loglevel = 6; filelist = load_filelist(argv[2]); if (!filelist) { fatal_error("Failed to load filelist"); } toggle_node_selection(filelist, FALSE); toggle_all_root_dirs_on(filelist); // BERLIOS: /usr/lib ??? toggle_path_selection(filelist, "/usr/share", TRUE); save_filelist(filelist, "/tmp/out.txt"); mr_asprintf(&a, argv[3]); mr_asprintf(&b, argv[4]); res = save_filelist_entries_in_common(a, filelist, b, FALSE); free_filelist(filelist); mr_free(a); mr_free(b); printf("res = %d", res); finish(0); } if (argc == 3 && strcmp(argv[1], "--popuplist") == 0) { popup_changelist_from_file(argv[2]); paranoid_MR_finish(0); } if (argc == 5 && strcmp(argv[1], "--copy") == 0) { mr_msg(1, "SCORE"); g_loglevel = 10; if (strstr(argv[2], "save")) { mr_msg(1, "Saving from %s to %s", argv[3], argv[4]); fin = fopen(argv[3], "r"); fout = fopen(argv[4], "w"); copy_from_src_to_dest(fin, fout, 'w'); fclose(fin); fin = fopen(argv[3], "r"); copy_from_src_to_dest(fin, fout, 'w'); fclose(fout); fclose(fin); } else if (strstr(argv[2], "restore")) { fout = fopen(argv[3], "w"); fin = fopen(argv[4], "r"); copy_from_src_to_dest(fout, fin, 'r'); fclose(fin); fin = fopen(argv[4], "r"); copy_from_src_to_dest(fout, fin, 'r'); fclose(fout); fclose(fin); } else { fatal_error("Unknown additional param"); } finish(0); } if (argc == 3 && strcmp(argv[1], "--mdstat") == 0) { wait_until_software_raids_are_prepped(argv[2], 100); finish(0); } if (argc == 3 && strcmp(argv[1], "--mdconv") == 0) { finish(create_raidtab_from_mdstat(argv[2])); } if (argc == 2 && strcmp(argv[1], "--live-grub") == 0) { retval = run_grub(FALSE, "/dev/hda"); if (retval) { log_to_screen(_("Failed to write Master Boot Record")); } paranoid_MR_finish(0); } if (argc == 3 && strcmp(argv[1], "--paa") == 0) { g_current_media_number = atoi(argv[2]); pause_and_ask_for_cdr(5, NULL); paranoid_MR_finish(0); } else if (!bkpinfo->disaster_recovery) { // live! if (argc != 1) { popup_and_OK (_ ("Live mode doesn't support command-line parameters yet.")); paranoid_MR_finish(1); } mr_msg(1, "I am in normal, live mode."); mr_msg(2, "FYI, MOUNTLIST_FNAME = %s", g_mountlist_fname); mount_boot_if_necessary(); /* for Gentoo users */ mr_msg(2, "Still here."); if (argc > 1 && strcmp(argv[argc - 1], "--live-from-cd") == 0) { g_restoring_live_from_cd = TRUE; } if (argc == 5 && strcmp(argv[1], "--monitas-live") == 0) { retval = restore_live_from_monitas_server(bkpinfo, argv[2], argv[3], argv[4]); } else { mr_msg(2, "Calling restore_to_live_filesystem()"); retval = restore_to_live_filesystem(bkpinfo); } mr_msg(2, "Still here. Yay."); if (strlen(bkpinfo->tmpdir) > 0) { mr_asprintf(&tmp, "rm -Rf %s/*", bkpinfo->tmpdir); run_program_and_log_output(tmp, FALSE); mr_free(tmp); } unmount_boot_if_necessary(); /* for Gentoo users */ paranoid_MR_finish(retval); } else { /* Disaster recovery mode (must be) */ mr_msg(1, "I must be in disaster recovery mode."); mr_msg(2, "FYI, MOUNTLIST_FNAME = %s ", g_mountlist_fname); if (argc == 3 && strcmp(argv[1], "--monitas-memorex") == 0) { log_to_screen(_("Uh, that hasn't been implemented yet.")); paranoid_MR_finish(1); } iamhere("About to call load_mountlist and load_raidtab"); strcpy(bkpinfo->restore_path, MNT_RESTORING); read_cfg_file_into_bkpinfo(g_mondo_cfg_file, bkpinfo); retval = load_mountlist(mountlist, g_mountlist_fname); retval += load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); iamhere ("Returned from calling load_mountlist and load_raidtab successfully"); if (argc > 1 && (strcmp(argv[1], "--compare") == 0 || strcmp(argv[1], "--nuke") == 0)) { if (bkpinfo->backup_media_type == nfs && !is_this_device_mounted(bkpinfo->nfs_mount)) { mr_msg(1, "Mounting nfs dir"); sprintf(bkpinfo->isodir, "/tmp/isodir"); run_program_and_log_output("mkdir -p /tmp/isodir", 5); mr_asprintf(&tmp, "mount %s -t nfs -o nolock /tmp/isodir", bkpinfo->nfs_mount); run_program_and_log_output(tmp, 1); mr_free(tmp); } } if (retval) { log_to_screen (_ ("Warning - load_raidtab_into_raidlist returned an error")); } mr_msg(1, "Send in the clowns."); if (argc == 2 && strcmp(argv[1], "--partition-only") == 0) { mr_msg(0, "Partitioning only."); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); strcpy(g_mountlist_fname, "/tmp/mountlist.txt"); load_mountlist(mountlist, g_mountlist_fname); res = partition_everything(mountlist); finish(res); } if (argc == 2 && strcmp(argv[1], "--format-only") == 0) { mr_msg(0, "Formatting only."); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); strcpy(g_mountlist_fname, "/tmp/mountlist.txt"); load_mountlist(mountlist, g_mountlist_fname); res = format_everything(mountlist, FALSE, raidlist); finish(res); } if (argc == 2 && strcmp(argv[1], "--stop-lvm-and-raid") == 0) { mr_msg(0, "Stopping LVM and RAID"); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); strcpy(g_mountlist_fname, "/tmp/mountlist.txt"); load_mountlist(mountlist, g_mountlist_fname); res = do_my_funky_lvm_stuff(TRUE, FALSE); res += stop_all_raid_devices(mountlist); finish(res); } if (argc == 2 && strcmp(argv[1], "--nuke") == 0) { iamhere("nuking"); retval += nuke_mode(bkpinfo, mountlist, raidlist); } else if (argc == 2 && strcmp(argv[1], "--interactive") == 0) { iamhere("catchall"); retval += catchall_mode(bkpinfo, mountlist, raidlist); } else if (argc == 2 && strcmp(argv[1], "--compare") == 0) { iamhere("compare"); retval += compare_mode(bkpinfo, mountlist, raidlist); } else if (argc == 2 && strcmp(argv[1], "--iso") == 0) { iamhere("iso"); retval = iso_mode(bkpinfo, mountlist, raidlist, FALSE); } else if (argc == 2 && strcmp(argv[1], "--mbr") == 0) { iamhere("mbr"); retval = mount_all_devices(mountlist, TRUE); if (!retval) { retval += run_boot_loader(FALSE); retval += unmount_all_devices(mountlist); } if (retval) { log_to_screen(_("Failed to write Master Boot Record")); } } else if (argc == 2 && strcmp(argv[1], "--isonuke") == 0) { iamhere("isonuke"); retval = iso_mode(bkpinfo, mountlist, raidlist, TRUE); } else if (argc != 1) { log_to_screen(_("Invalid parameters")); paranoid_MR_finish(1); } else { iamhere("catchall (no mode specified in command-line call"); retval += catchall_mode(bkpinfo, mountlist, raidlist); } } /* clean up at the end */ if (retval) { if (does_file_exist("/tmp/changed.files")) { log_to_screen (_ ("See /tmp/changed.files for list of files that have changed.")); } mvaddstr_and_log_it(g_currentY++, 0, _ ("Run complete. Errors were reported. Please review the logfile.")); } else { if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) { mvaddstr_and_log_it(g_currentY++, 0, _ ("Run complete. Please remove floppy/CD/media and reboot.")); } else { run_program_and_log_output("sync", FALSE); if (is_this_device_mounted(MNT_CDROM)) { res = run_program_and_log_output("umount " MNT_CDROM, FALSE); } else { res = 0; } if (!bkpinfo->please_dont_eject) { res = eject_device("/dev/cdrom"); } mvaddstr_and_log_it(g_currentY++, 0, _ ("Run complete. Please remove media and reboot.")); } } // g_I_have_just_nuked is set true by nuke_mode() just before it returns if (!system("which post-nuke > /dev/null 2> /dev/null")) { mr_msg(1, "post-nuke found; find out whether we should run it..."); if (g_I_have_just_nuked || does_file_exist("/POST-NUKE-ANYWAY")) { run_postnuke = TRUE; mr_msg(1, "Yes, will run post-nuke because in nuke mode or file /POST-NUKE-ANYWAY exists."); } else if (ask_me_yes_or_no("post-nuke script found. Do you want to run it?")) { run_postnuke = TRUE; mr_msg(1, "Yes, will run post-nuke because user interactively asked for it."); } else { run_postnuke = FALSE; mr_msg(1, "No, will not run post-nuke."); } } else { mr_msg(1, "No post-nuke found."); } if (run_postnuke) { log_to_screen("Running post-nuke..."); if (mount_all_devices(mountlist, TRUE)) { log_to_screen ("Unable to re-mount partitions for post-nuke stuff"); } else { mr_msg(1, "Re-mounted partitions for post-nuke stuff"); mr_asprintf(&tmp, "post-nuke %s %d", bkpinfo->restore_path, retval); mr_msg(2, "Calling '%s'", tmp); if ((res = run_program_and_log_output(tmp, 0))) { log_OS_error(tmp); } mr_free(tmp); mr_msg(1, "post-nuke returned w/ res=%d", res); } unmount_all_devices(mountlist); log_to_screen("I've finished post-nuking."); } unlink("/tmp/mondo-run-prog.tmp"); set_signals(FALSE); mr_asprintf(&tmp, "rm -Rf %s", bkpinfo->tmpdir); run_program_and_log_output(tmp, FALSE); mr_free(tmp); log_to_screen (_ ("Restore log copied to /tmp/mondo-restore.log on your hard disk")); log_to_screen(_("Mondo-restore is exiting (retval=%d)"), retval); mr_asprintf(&tmp, "umount %s", bkpinfo->isodir); run_program_and_log_output(tmp, 5); mr_free(tmp); mr_free(mountlist); mr_free(raidlist); if (am_I_in_disaster_recovery_mode()) { run_program_and_log_output("mount / -o remount,rw", 2); } // for b0rken distros paranoid_MR_finish(retval); // frees global stuff plus bkpinfo free_libmondo_global_strings(); // it's fine to have this here :) really :) unlink("/tmp/filelist.full"); unlink("/tmp/filelist.full.gz"); exit(retval); } /************************************************************************** *END_MAIN * **************************************************************************/ /************************************************************************** *END_MONDO-RESTORE.C * **************************************************************************/