/***************************************************************************
$Id: mondoarchive.c 3060 2012-11-10 04:05:37Z bruno $
* The main file for mondoarchive.
*/

/************************* #include statements *************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "my-stuff.h"
#include "mr_mem.h"
#include "../common/mondostructures.h"
#include "../common/libmondo.h"
#include "../common/libmondo-cli-EXT.h"
#include "../common/libmondo-tools-EXT.h"
#include "mondoarchive.h"

// for CVS
//static char cvsid[] = "$Id: mondoarchive.c 3060 2012-11-10 04:05:37Z bruno $";

/************************* external variables *************************/
extern void set_signals(int);
extern int g_current_media_number;
extern int g_currentY;
extern bool g_text_mode;
extern char *g_boot_mountpt;
extern bool g_remount_floppy_at_end;
extern char *g_cdrw_drive_is_here;
static char *g_cdrom_drive_is_here = NULL;
static char *g_dvd_drive_is_here = NULL;
extern double g_kernel_version;

/***************** global vars, used only by main.c ******************/
long diffs;

extern t_bkptype g_backup_media_type;
extern int g_loglevel;

/**
 * Whether we're restoring from ISOs. Obviously not, since this is the
 * backup program.
 * @note You @b MUST declare this variable somewhere in your program if
 * you use libmondo. Otherwise the link will fail.
 * @ingroup globalGroup
 */
bool g_ISO_restore_mode = FALSE;

/* Do we use extended attributes and acl ?
 *  * By default no, use --acl & --attr options to force their usage */
char *g_getfacl = NULL;
char *g_getfattr = NULL;

/* Reference to global bkpinfo */
struct s_bkpinfo *bkpinfo;

/* No cleanup for the moment */
void (*mr_cleanup)(void) = NULL;

/* To be coded */
void free_MR_global_filenames(void) {
}

/****************** subroutines used only by main.c ******************/


/**
 * Print a "don't panic" message to the log and a message about the logfile to the screen.
 */
void welcome_to_mondoarchive(void)
{
	char *tmp = NULL;

	log_msg(0, "Mondo Archive v%s --- http://www.mondorescue.org",
			PACKAGE_VERSION);
	log_msg(0, "running %s binaries", get_architecture());
	tmp = get_uname_m();
	log_msg(0, "running on %s architecture", tmp);
	mr_free(tmp);
	log_msg(0,
			"-----------------------------------------------------------");
	log_msg(0,
			"NB: Mondo logs almost everything, so don't panic if you see");
	log_msg(0,
			"some error messages.  Please read them carefully before you");
	log_msg(0,
			"decide to break out in a cold sweat.    Despite (or perhaps");
	log_msg(0,
			"because of) the wealth of messages. some users are inclined");
	log_msg(0,
			"to stop reading this log. If Mondo stopped for some reason,");
	log_msg(0,
			"chances are it's detailed here.  More than likely there's a");
	log_msg(0,
			"message at the very end of this log that will tell you what");
	log_msg(0,
			"is wrong. Please read it!                          -Devteam");
	log_msg(0,
			"-----------------------------------------------------------");

	log_msg(0, "Zero...");
	log_msg(1, "One...");
	log_msg(2, "Two...");
	log_msg(3, "Three...");
	log_msg(4, "Four...");
	log_msg(5, "Five...");
	log_msg(6, "Six...");
	log_msg(7, "Seven...");
	log_msg(8, "Eight...");
	printf("See %s for details of backup run.\n", MONDO_LOGFILE);
}


extern char *g_magicdev_command;

/**
 * Do whatever is necessary to insure a successful backup on the Linux distribution
 * of the day.
 */
void distro_specific_kludges_at_start_of_mondoarchive(void)
{
	log_msg(2, "Unmounting old ramdisks if necessary");
	stop_magicdev_if_necessary();	// for RH+Gnome users
	/*
	run_program_and_log_output
		("umount `mount | grep shm | grep mondo | cut -d' ' -f3`", 2);
		*/
	unmount_supermounts_if_necessary();	// for Mandrake users whose CD-ROMs are supermounted
	//  stop_autofs_if_necessary(); // for Xandros users
	mount_boot_if_necessary();	// for Gentoo users with non-mounted /boot partitions
	clean_up_KDE_desktop_if_necessary();	// delete various misc ~/.* files that get in the way
}



/**
 * Undo whatever was done by distro_specific_kludges_at_start_of_mondoarchive().
 */
void distro_specific_kludges_at_end_of_mondoarchive(void)
{
	log_msg(2, "Restarting magicdev if necessary");
	sync();
	restart_magicdev_if_necessary();	// for RH+Gnome users

	log_msg(2, "Restarting autofs if necessary");
	sync();
	//  restart_autofs_if_necessary(); // for Xandros users

	log_msg(2, "Restarting supermounts if necessary");
	sync();
	remount_supermounts_if_necessary();	// for Mandrake users

	log_msg(2, "Unmounting /boot if necessary");
	sync();
	unmount_boot_if_necessary();	// for Gentoo users

//  log_msg( 2, "Cleaning up KDE desktop");
//  clean_up_KDE_desktop_if_necessary();
}


/**
 * Backup/verify the user's data.
 * What did you think it did, anyway? :-)
 */
int main(int argc, char *argv[])
{
	char *tmp = NULL;
	char *tmp1 = NULL;
	int res, retval;
	char *say_at_end = NULL;
	FILE *fin = NULL;

/* Make sure I'm root; abort if not */
	if (getuid() != 0) {
		fprintf(stderr, "Please run as root.\r\n");
		exit(127);
	}

/* If -V, -v or --version then echo version no. and quit */
	if (argc == 2
		&& (!strcmp(argv[argc - 1], "-v") || !strcmp(argv[argc - 1], "-V")
			|| !strcmp(argv[argc - 1], "--version"))) {
		printf("mondoarchive v%s\nSee man page for help\n", PACKAGE_VERSION);
		exit(0);
	}

/* Initialize variables */

	printf("Initializing...\n");
	if (!(bkpinfo = (struct s_bkpinfo *)malloc(sizeof(struct s_bkpinfo)))) {
		fatal_error("Cannot malloc bkpinfo");
	}
	reset_bkpinfo();

	res = 0;
	retval = 0;
	diffs = 0;
	malloc_libmondo_global_strings();

	/* initialize log file with time stamp */
	unlink(MONDO_LOGFILE);
	log_msg(0, "Time started: %s", mr_date());

	/* make sure PATH environmental variable allows access to mkfs, fdisk, etc. */
	mr_asprintf(&tmp1,"%s:/sbin:/usr/sbin:/usr/local/sbin",getenv("PATH"));
	setenv("PATH", tmp1, 1);
	paranoid_free(tmp1);

	/* Add the ARCH environment variable for ia64 purposes */
	mr_asprintf(&tmp1,"%s",get_architecture());
	setenv("ARCH", tmp1, 1);
	paranoid_free(tmp1);

	/* Add MONDO_SHARE environment variable for mindi */
	setenv_mondo_share();

	/* Configure the bkpinfo structure, global file paths, etc. */
	g_main_pid = getpid();
	log_msg(9, "This");

	set_signals(TRUE);			// catch SIGTERM, etc.
	run_program_and_log_output("dmesg -n1", TRUE);

	log_msg(9, "Next");
	make_hole_for_dir(MONDO_CACHE);

	welcome_to_mondoarchive();
	distro_specific_kludges_at_start_of_mondoarchive();
	g_kernel_version = get_kernel_version();

	if (argc == 4 && !strcmp(argv[1], "getfattr")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		if (!strstr(argv[2], "filelist")) {
			printf("Sorry - filelist goes first\n");
			finish(1);
		} else {
			finish(get_fattr_list(argv[2], argv[3]));
		}
		finish(0);
	}
	if (argc == 4 && !strcmp(argv[1], "setfattr")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		finish(set_fattr_list(argv[2], argv[3]));
	}

	if (argc == 3 && !strcmp(argv[1], "wildcards")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		malloc_string(tmp);
		turn_wildcard_chars_into_literal_chars(tmp, argv[2]);
		printf("in=%s; out=%s\n", argv[2], tmp);
		paranoid_free(tmp);
		finish(1);
	}

	if (argc == 4 && !strcmp(argv[1], "getfacl")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		if (!strstr(argv[2], "filelist")) {
			printf("Sorry - filelist goes first\n");
			finish(1);
		} else {
			finish(get_acl_list(argv[2], argv[3]));
		}
		finish(0);
	}
	if (argc == 4 && !strcmp(argv[1], "setfacl")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		finish(set_acl_list(argv[2], argv[3]));
	}
	if (argc >= 2 && !strcmp(argv[1], "mkraidtab")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
#undef MDSTAT_FILE
#define MDSTAT_FILE "/tmp/mdstat"
		if (!(fin = fopen(MDSTAT_FILE, "r"))) {
			log_msg(1, "Could not open %s.\n", MDSTAT_FILE);
    			finish(1);
		}

		create_raidtab_from_mdstat(MDSTAT_FILE,"/tmp/raidtab");
		finish(0);
	}

	if (argc > 2 && !strcmp(argv[1], "find-cd")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		malloc_string(tmp);
		if (find_cdrw_device(tmp)) {
			printf("Failed to find CDR-RW drive\n");
		} else {
			printf("CD-RW is at %s\n", tmp);
		}
		tmp[0] = '\0';
		if (find_cdrom_device(tmp, atoi(argv[2]))) {
			printf("Failed to find CD-ROM drive\n");
		} else {
			printf("CD-ROM is at %s\n", tmp);
		}
		paranoid_free(tmp);
		finish(0);
	}

	if (argc > 2 && !strcmp(argv[1], "find-dvd")) {
		g_loglevel = 10;
		g_text_mode = TRUE;
		setup_newt_stuff();
		malloc_string(tmp);
		if (find_dvd_device(tmp, atoi(argv[2]))) {
			printf("Failed to find DVD drive\n");
		} else {
			printf("DVD is at %s\n", tmp);
		}
		paranoid_free(tmp);
		finish(0);
	}

	if (argc > 2 && !strcmp(argv[1], "disksize")) {
		printf("%s --> %ld\n", argv[2], get_phys_size_of_drive(argv[2]));
		finish(0);
	}
	if (argc > 2 && !strcmp(argv[1], "test-dev")) {
		if (is_dev_an_NTFS_dev(argv[2])) {
			printf("%s is indeed an NTFS dev\n", argv[2]);
		} else {
			printf("%s is _not_ an NTFS dev\n", argv[2]);
		}
		finish(0);
	}

	if (pre_param_configuration()) {
		fatal_error
			("Pre-param initialization phase failed. Please review the error messages above, make the specified changes, then try again. Exiting...");
	}

/* Process command line, if there is one. If not, ask user for info. */
	if (argc == 1) {
		g_text_mode = FALSE;
		setup_newt_stuff();
		res = interactively_obtain_media_parameters_from_user(TRUE);	/* yes, archiving */
		if (res) {
			fatal_error
				("Syntax error. Please review the parameters you have supplied and try again.");
		}
	} else {
		res = handle_incoming_parameters(argc, argv);
		if (res) {
			printf
				("Errors were detected in the command line you supplied.\n");
			printf("Please review the log file - %s\n", MONDO_LOGFILE );
			log_msg(1, "Mondoarchive will now exit.");
			finish(1);
		}
		setup_newt_stuff();
	}

/* Finish configuring global structures */
	if (post_param_configuration()) {
		fatal_error
			("Post-param initialization phase failed. Perhaps bad parameters were supplied to mondoarchive? Please review the documentation, error messages and logs. Exiting...");
	}

	log_to_screen
		("BusyBox's sources are available from http://www.busybox.net");

	/* If we're meant to backup then backup */
	if (bkpinfo->backup_data) {
		res = backup_data();
		retval += res;
		if (res) {
			mr_asprintf(&say_at_end, "Data archived. Please check the logs, just as a precaution. ");
		} else {
			mr_asprintf(&say_at_end, "Data archived OK. ");
		}
	}

/* If we're meant to verify then verify */
	if (bkpinfo->verify_data) {
		res = verify_data();
		if (res < 0) {
			mr_asprintf(&tmp, "%d difference%c found.", -res,
					(-res != 1) ? 's' : ' ');
			mr_asprintf(&say_at_end, "%s", tmp);
			log_to_screen(tmp);
			mr_free(tmp);
			res = 0;
		}
		retval += res;
	}

/* Report result of entire operation (success? errors?) */
	if (!retval) {
		mvaddstr_and_log_it(g_currentY++, 0,
							"Backup and/or verify ran to completion. Everything appears to be fine.");
	} else {
		mvaddstr_and_log_it(g_currentY++, 0,
							"Backup and/or verify ran to completion. However, errors did occur.");
	}

	if (does_file_exist(MINDI_CACHE"/mondorescue.iso")) {
		log_to_screen
			(MINDI_CACHE"/mondorescue.iso, a boot/utility CD, is available if you want it.");
	}

	if (length_of_file(MONDO_CACHE"/changed.files") > 2) {
		if (g_text_mode) {
			log_to_screen("Type 'less "MONDO_CACHE"/changed.files' to see which files don't match the archives");
		} else {
			log_msg(1, "Type 'less "MONDO_CACHE"/changed.files' to see which files don't match the archives");
			log_msg(2, "Calling popup_changelist_from_file()");
			popup_changelist_from_file(MONDO_CACHE"/changed.files");
			log_msg(2, "Returned from popup_changelist_from_file()");
		}
	} else {
		unlink(MONDO_CACHE"/changed.files");
	}
	if (say_at_end != NULL) {
		log_to_screen(say_at_end);
		paranoid_free(say_at_end);
	}
	mr_asprintf(&tmp, "umount %s/tmpfs", bkpinfo->tmpdir);
	run_program_and_log_output(tmp, TRUE);
	mr_free(tmp);
	if (bkpinfo->backup_media_type == usb) {
		log_msg(1, "Unmounting USB device.");
		mr_asprintf(&tmp, "umount %s1", bkpinfo->media_device);
		run_program_and_log_output(tmp, TRUE);
		mr_free(tmp);
	}

	run_program_and_log_output("mount", 2);

	paranoid_system("rm -f "MONDO_CACHE"/last-backup.aborted");
	if (!retval) {
		printf("Mondoarchive ran OK.\n");
	} else {
		printf("Errors occurred during backup. Please check logfile.\n");
	}
	distro_specific_kludges_at_end_of_mondoarchive();
	set_signals(FALSE);

	free_libmondo_global_strings();
	

	if (!g_cdrom_drive_is_here) {
		log_msg(10, "FYI, g_cdrom_drive_is_here was never used");
	}
	if (!g_dvd_drive_is_here) {
		log_msg(10, "FYI, g_dvd_drive_is_here was never used");
	}

	/* finalize log file with time stamp */
	log_msg(0, "Time finished: %s", mr_date());

	if (chdir("/tmp")) {
		// FIXME
	}

	if (!g_text_mode) {
		popup_and_OK
			("Mondo Archive has finished its run. Please press ENTER to return to the shell prompt.");
		log_to_screen("See %s for details of backup run.", MONDO_LOGFILE);
	} else {
		printf("See %s for details of backup run.\n", MONDO_LOGFILE);
	}
	finish(retval);

	return EXIT_SUCCESS;
}
