/**
 * Generate a list of the files that have changed, based on @c afio @c -r
 * messages.
 * @param changedfiles_fname Filename of the place to put a list of afio's reported changed.
 * @param ignorefiles_fname Filename of a list of files to ignore (use "" if none).
 * @param stderr_fname File containing afio's stderr output.
 * @return The number of differences found (0 for a perfect backup).
 * @bug This function seems orphaned.
 * @ingroup utilityGroup
 */
long
generate_list_of_changed_files(char *changedfiles_fname,
							   char *ignorefiles_fname, char *stderr_fname)
{
	/*@ buffer ********************************************************** */
	char *command;
	char *afio_found_changes;

	/*@ int ************************************************************* */
	int res = 0;

	/*@ long ************************************************************ */
	long afio_diffs = 0;

	command = malloc(2000);
	afio_found_changes = malloc(500);
	assert_string_is_neither_NULL_nor_zerolength(changedfiles_fname);
	assert_string_is_neither_NULL_nor_zerolength(ignorefiles_fname);
	assert_string_is_neither_NULL_nor_zerolength(stderr_fname);

	sprintf(afio_found_changes, "%s.afio", ignorefiles_fname);
	paranoid_system("sync");

/*  sprintf (command,
	   "cat %s | grep \"afio: \" | awk '{j=substr($0,8); i=index(j,\": \");printf \"/%%s\\n\",substr(j,1,i-2);}' | sort | uniq | grep -v \"incheckentry.*xwait\" | grep -vx \"/afio:.*\" | grep -vx \"/dev/.*\" > %s",
	   stderr_fname, afio_found_changes);
*/

	log_msg(1, "Now scanning log file for 'afio: ' stuff");
	sprintf(command,
			"cat %s | grep \"afio: \" | sed 's/afio: //' | grep -vx \"/dev/.*\" >> %s",
			stderr_fname, afio_found_changes);
	log_msg(2, command);
	res = system(command);
	if (res) {
		log_msg(2, "Warning - failed to think");
	}

	log_msg(1, "Now scanning log file for 'star: ' stuff");
	sprintf(command,
			"cat %s | grep \"star: \" | sed 's/star: //' | grep -vx \"/dev/.*\" >> %s",
			stderr_fname, afio_found_changes);
	log_msg(2, command);
	res = system(command);
	if (res) {
		log_msg(2, "Warning - failed to think");
	}
//  exclude_nonexistent_files (afio_found_changes);
	afio_diffs = count_lines_in_file(afio_found_changes);
	sprintf(command,
			"cat %s %s %s | sort | uniq -c | awk '{ if ($1==\"2\") {print $2;};}' | grep -v \"incheckentry xwait()\" > %s",
			ignorefiles_fname, afio_found_changes, afio_found_changes,
			changedfiles_fname);
	log_msg(2, command);
	paranoid_system(command);
	paranoid_free(command);
	paranoid_free(afio_found_changes);
	return (afio_diffs);
}
/**
 * Compare all data on a CD-R/CD-RW/DVD/ISO/NFS-based backup.
 * @param bkpinfo The backup information structure. Passed to other functions.
 * @return 0 for success, nonzero for failure.
 */
int compare_to_CD(struct s_bkpinfo *bkpinfo)
{
  /** needs malloc *********/
	char *tmp, *cwd, *new, *command;
	int resA = 0;
	int resB = 0;
	long noof_changed_files;

	malloc_string(tmp);
	malloc_string(cwd);
	malloc_string(new);
	malloc_string(command);

	assert(bkpinfo != NULL);

	getcwd(cwd, MAX_STR_LEN - 1);
	chdir(bkpinfo->restore_path);
	getcwd(new, MAX_STR_LEN - 1);
	sprintf(tmp, "new path is %s", new);
	insist_on_this_cd_number(bkpinfo, g_current_media_number);
	unlink("/tmp/changed.txt");

	resA = compare_all_tarballs(bkpinfo);
	resB = compare_all_biggiefiles(bkpinfo);
	chdir(cwd);
	noof_changed_files = count_lines_in_file("/tmp/changed.txt");
	if (noof_changed_files) {
		sprintf(tmp, "%ld files do not match the backup            ",
				noof_changed_files);
		//      mvaddstr_and_log_it( g_currentY++, 0, tmp );
		log_to_screen(tmp);
		sprintf(command, "cat /tmp/changed.txt >> %s", MONDO_LOGFILE);
		paranoid_system(command);
	} else {
		sprintf(tmp, "All files match the backup                     ");
		mvaddstr_and_log_it(g_currentY++, 0, tmp);
		log_to_screen(tmp);
	}

	paranoid_free(tmp);
	paranoid_free(cwd);
	paranoid_free(new);
	paranoid_free(command);

	return (resA + resB);
}
/**
 * Compare all biggiefiles in the backup.
 * @param bkpinfo The backup information structure. Used only in compare_a_biggiefile().
 * @return 0 for success, nonzero for failure.
 */
int compare_all_biggiefiles(struct s_bkpinfo *bkpinfo)
{
	int retval = 0;
	int res;
	long noof_biggiefiles, bigfileno = 0;
	char tmp[MAX_STR_LEN];

	assert(bkpinfo != NULL);
	log_msg(1, "Comparing biggiefiles");

	if (length_of_file(BIGGIELIST) < 6) {
		log_msg(1,
				"OK, really teeny-tiny biggielist; not comparing biggiefiles");
		return (0);
	}
	noof_biggiefiles = count_lines_in_file(BIGGIELIST);
	if (noof_biggiefiles <= 0) {
		log_msg(1, "OK, no biggiefiles; not comparing biggiefiles");
		return (0);
	}
	mvaddstr_and_log_it(g_currentY, 0,
						"Comparing large files                                                  ");
	open_progress_form("Comparing large files",
					   "I am now comparing the large files",
					   "against the filesystem. Please wait.", "",
					   noof_biggiefiles);
	for (bigfileno = 0; bigfileno < noof_biggiefiles; bigfileno++) {
		sprintf(tmp, "Comparing big file #%ld", bigfileno + 1);
		log_msg(1, tmp);
		update_progress_form(tmp);
		res = compare_a_biggiefile(bkpinfo, bigfileno);
		retval += res;
		g_current_progress++;
	}
	close_progress_form();
	return (0);
	if (retval) {
		mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
	} else {
		mvaddstr_and_log_it(g_currentY++, 74, "Done.");
	}
	return (retval);
}
/**
 * Pop up a list containing the filenames in @p source_file and the severity if they have changed since the
 * last backup. There can be no more than @p ARBITRARY_MAXIMUM files in @p source_file.
 * @param source_file The file containing a list of changed files.
 */
	void popup_changelist_from_file(char *source_file) {
		char *reason = NULL;
		newtComponent myForm;
		newtComponent bClose;
		newtComponent bSelect;
		newtComponent b_res;
		newtComponent fileListbox;
		newtComponent headerMsg;

		/*@ ???? ************************************************************ */
		void *curr_choice;
		void *keylist[ARBITRARY_MAXIMUM];

		/*@ int ************************************************************* */
		int i = 0;
		int currline = 0;
		int finished = FALSE;
		long lng = 0;

		/*@ buffers ********************************************************* */
		char *tmp;
		char *differ_sz;

		struct s_filelist *filelist;
		assert_string_is_neither_NULL_nor_zerolength(source_file);
		if (g_text_mode) {
			log_msg(2, "Text mode. Therefore, no popup list.");
			return;
		}
		log_msg(2, "Examining file %s", source_file);

		lng = count_lines_in_file(source_file);
		if (lng < 1) {
			log_msg(2, "No lines in file. Therefore, no popup list.");
			return;
		} else if (lng >= ARBITRARY_MAXIMUM) {
			log_msg(2, "Too many files differ for me to list.");
			return;
		}

		filelist = (struct s_filelist *) malloc(sizeof(struct s_filelist));
		fileListbox =
			newtListbox(2, 2, 12, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
		newtListboxClear(fileListbox);

		if (load_filelist_into_array(filelist, source_file)) {
			log_msg(2, "Can't open %s; therefore, cannot popup list",
					source_file);
			return;
		}
		log_msg(2, "%d files loaded into filelist array",
				filelist->entries);
		for (i = 0; i < filelist->entries; i++) {
			keylist[i] = (void *) i;
			newtListboxAppendEntry(fileListbox,
								   filelist_entry_to_string(&
															(filelist->
															 el[i])),
								   keylist[i]);
		}
		asprintf(&differ_sz,
				 _("  %d files differ. Hit 'Select' to pick a file. Hit 'Close' to quit the list."),
				 i);
		newtPushHelpLine(differ_sz);
		paranoid_free(differ_sz);

		bClose = newtCompactButton(10, 15, _(" Close  "));
		bSelect = newtCompactButton(30, 15, _(" Select "));
		asprintf(&tmp, "%-10s               %-20s", _("Priority"),
				 _("Filename"));
		headerMsg = newtLabel(2, 1, tmp);
		paranoid_free(tmp);

		newtOpenWindow(5, 4, 70, 16, _("Non-matching files"));
		myForm = newtForm(NULL, NULL, 0);
		newtFormAddComponents(myForm, headerMsg, fileListbox, bClose,
							  bSelect, NULL);
		while (!finished) {
			b_res = newtRunForm(myForm);
			if (b_res == bClose) {
				finished = TRUE;
			} else {
				curr_choice = newtListboxGetCurrent(fileListbox);
				for (i = 0;
					 i < filelist->entries && keylist[i] != curr_choice;
					 i++);
				if (i == filelist->entries && filelist->entries > 0) {
					log_to_screen(_("I don't know what that button does!"));
				} else {
					currline = i;
					if (filelist->entries > 0) {
						severity_of_difference(filelist->el[currline].
											   filename, reason);
						asprintf(&tmp, "%s --- %s",
								 filelist->el[currline].filename, reason);
						popup_and_OK(tmp);
						paranoid_free(tmp);
						paranoid_free(reason);
					}
				}
			}
		}
		newtFormDestroy(myForm);
		newtPopWindow();
		newtPopHelpLine();
	}
/**
 * Compare all data in the user's backup.
 * This function will mount filesystems, compare afioballs and biggiefiles,
 * and show the user the differences.
 * @param bkpinfo The backup information structure. Passed to other functions.
 * @param mountlist The mountlist containing partitions to mount.
 * @param raidlist The raidlist containing the user's RAID devices.
 * @return The number of errors/differences found.
 */
int
compare_mode(struct s_bkpinfo *bkpinfo,
			 struct mountlist_itself *mountlist,
			 struct raidlist_itself *raidlist)
{
	int retval = 0;
	long q;
	char *tmp;

	malloc_string(tmp);

  /**************************************************************************
   * also deletes tmp/filelist.full & tmp/biggielist.txt _and_ tries to     *
   * restore them from start of tape, if available                          *
   **************************************************************************/
	assert(bkpinfo != NULL);
	assert(mountlist != NULL);
	assert(raidlist != NULL);

	while (get_cfg_file_from_archive(bkpinfo)) {
		if (!ask_me_yes_or_no
			("Failed to find config file/archives. Choose another source?"))
		{
			fatal_error("Unable to find config file/archives. Aborting.");
		}
		interactively_obtain_media_parameters_from_user(bkpinfo, FALSE);
	}

	read_cfg_file_into_bkpinfo(g_mondo_cfg_file, bkpinfo);
	g_current_media_number = 1;
	mvaddstr_and_log_it(1, 30, "Comparing Automatically");
	iamhere("Pre-MAD");
	retval = mount_all_devices(mountlist, FALSE);
	iamhere("Post-MAD");
	if (retval) {
		unmount_all_devices(mountlist);
		return (retval);
	}
	if (bkpinfo->backup_media_type == tape
		|| bkpinfo->backup_media_type == udev) {
		retval += compare_to_tape(bkpinfo);
	} else if (bkpinfo->backup_media_type == cdstream) {
		retval += compare_to_cdstream(bkpinfo);
	} else {
		retval += compare_to_CD(bkpinfo);
	}
	if (retval) {
		mvaddstr_and_log_it(g_currentY++,
							0,
							"Warning - differences found during the compare phase");
	}

	retval += unmount_all_devices(mountlist);

	if (count_lines_in_file("/tmp/changed.txt") > 0) {
		mvaddstr_and_log_it(g_currentY++, 0,
							"Differences found while files were being compared.");
		streamline_changes_file("/tmp/changed.files", "/tmp/changed.txt");
		if (count_lines_in_file("/tmp/changed.files") <= 0) {
			mvaddstr_and_log_it(g_currentY++, 0,
								"...but they were logfiles and temporary files. Your archives are fine.");
			log_to_screen
				("The differences were logfiles and temporary files. Your archives are fine.");
		} else {
			q = count_lines_in_file("/tmp/changed.files");
			sprintf(tmp, "%ld significant difference%s found.", q,
					(q != 1) ? "s" : "");
			mvaddstr_and_log_it(g_currentY++, 0, tmp);
			log_to_screen(tmp);

			strcpy(tmp,
				   "Type 'less /tmp/changed.files' for a list of non-matching files");
			mvaddstr_and_log_it(g_currentY++, 0, tmp);
			log_to_screen(tmp);

			log_msg(2, "calling popup_changelist_from_file()");
			popup_changelist_from_file("/tmp/changed.files");
			log_msg(2, "Returning from popup_changelist_from_file()");
		}
	} else {
		log_to_screen
			("No significant differences were found. Your backup is perfect.");
	}
	kill_petris();
	paranoid_free(tmp);
	return (retval);
}
/**
 * Compare afioball @p tarball_fname against the filesystem.
 * You must be chdir()ed to the directory where the filesystem is mounted
 * before you call this function.
 * @param tarball_fname The filename of the tarball to compare.
 * @param current_tarball_number The fileset number contained in @p tarball_fname.
 * @return 0 for success, nonzero for failure.
 */
int compare_a_tarball(char *tarball_fname, int current_tarball_number)
{
	int retval = 0;
	int res;
	long noof_lines;
	long archiver_errors;
	bool use_star;

  /***  needs malloc *********/
	char *command, *tmp, *filelist_name, *logfile, *archiver_exe,
		*compressor_exe;

	malloc_string(command);
	malloc_string(tmp);
	malloc_string(filelist_name);
	malloc_string(logfile);
	malloc_string(archiver_exe);
	malloc_string(compressor_exe);

	use_star = (strstr(tarball_fname, ".star")) ? TRUE : FALSE;
	assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
	sprintf(logfile, "/tmp/afio.log.%d", current_tarball_number);
	sprintf(filelist_name, MNT_CDROM "/archives/filelist.%d",
			current_tarball_number);

	noof_lines = count_lines_in_file(filelist_name);

	if (strstr(tarball_fname, ".bz2")) {
		strcpy(compressor_exe, "bzip2");
	} else if (strstr(tarball_fname, ".lzo")) {
		strcpy(compressor_exe, "lzop");
	} else {
		compressor_exe[0] = '\0';
	}

	if (use_star) {
		strcpy(archiver_exe, "star");
	} else {
		strcpy(archiver_exe, "afio");
	}

	if (compressor_exe[0]) {
		strcpy(tmp, compressor_exe);
		if (!find_home_of_exe(tmp)) {
			fatal_error("(compare_a_tarball) Compression program missing");
		}
		if (use_star)			// star
		{
			if (!strcmp(compressor_exe, "bzip2")) {
				strcat(archiver_exe, " -bz");
			} else {
				fatal_error
					("(compare_a_tarball) Please use only bzip2 with star");
			}
		} else					// afio
		{
			sprintf(compressor_exe, "-P %s -Z", tmp);
		}
	}
// star -diff H=star -bz file=....

#ifdef __FreeBSD__
#define BUFSIZE 512L
#else
#define BUFSIZE (1024L*1024L)/TAPE_BLOCK_SIZE
#endif
	if (use_star)				// doesn't use compressor_exe
	{
		sprintf(command,
				"%s -diff H=star file=%s >> %s 2>> %s",
				archiver_exe, tarball_fname, logfile, logfile);
	} else {
		sprintf(command,
				"%s -r -b %ld -M 16m -c %ld %s %s >> %s 2>> %s",
				archiver_exe,
				TAPE_BLOCK_SIZE,
				BUFSIZE, compressor_exe, tarball_fname, logfile, logfile);
	}
#undef BUFSIZE

	res = system(command);
	retval += res;
	if (res) {
		log_OS_error(command);
		sprintf(tmp, "Warning - afio returned error = %d", res);
	}
	if (length_of_file(logfile) > 5) {
		sprintf(command,
				"sed s/': \\\"'/\\|/ %s | sed s/'\\\": '/\\|/ | cut -d'|' -f2 | sort -u | grep -vx \"dev/.*\" >> /tmp/changed.txt",
				logfile);
		system(command);
		archiver_errors = count_lines_in_file(logfile);
	} else {
		archiver_errors = 0;
	}
	sprintf(tmp, "%ld difference%c in fileset #%d          ",
			archiver_errors, (archiver_errors != 1) ? 's' : ' ',
			current_tarball_number);
	if (archiver_errors) {
		sprintf(tmp,
				"Differences found while processing fileset #%d       ",
				current_tarball_number);
		log_msg(1, tmp);
	}
	unlink(logfile);
	paranoid_free(command);
	paranoid_free(tmp);
	paranoid_free(filelist_name);
	paranoid_free(logfile);
	malloc_string(archiver_exe);
	malloc_string(compressor_exe);
	return (retval);
}
/**
 * Verify all backups on tape.
 * This should be done after the backup process has already closed the tape.
 * @param bkpinfo The backup information structure. Passed to various helper functions.
 * @return 0 for success (even if thee were differences), nonzero for failure.
 * @ingroup verifyGroup
 */
int verify_tape_backups(struct s_bkpinfo *bkpinfo)
{

	/*@ int ************************************************************ */
	int retval = 0;

	/*@ buffers ******************************************************** */
	char tmp[MAX_STR_LEN];
	char changed_files_fname[MAX_STR_LEN];

	/*@ long *********************************************************** */
	long diffs = 0;

	assert(bkpinfo != NULL);

	log_msg(3, "verify_tape_backups --- starting");
	log_to_screen("Verifying backups");
	openin_tape(bkpinfo);
/* verify archives themselves */
	retval += verify_afioballs_from_stream(bkpinfo);
	retval += verify_biggiefiles_from_stream(bkpinfo);
/* find the final blocks */
	paranoid_system("sync");
	sleep(2);
	closein_tape(bkpinfo);
/* close tape; exit */
//  fclose(g_tape_stream); <-- not needed; is handled by closein_tape()
	paranoid_system
		("rm -f /tmp/biggies.changed /tmp/changed.files.[0-9]* 2> /dev/null");
	sprintf(changed_files_fname, "/tmp/changed.files.%d",
			(int) (random() % 32767));
	sprintf(tmp,
			"cat %s | grep -x \"%s:.*\" | cut -d'\"' -f2 | sort -u | awk '{print \"/\"$0;};' | tr -s '/' '/' | grep -v \"(total of\" | grep -v \"incheckentry.*xwait\" | grep -vx \"/afio:.*\" | grep -vx \"dev/.*\"  > %s",
			MONDO_LOGFILE, (bkpinfo->use_star) ? "star" : "afio",
			changed_files_fname);
	log_msg(2, "Running command to derive list of changed files");
	log_msg(2, tmp);
	if (system(tmp)) {
		if (does_file_exist(changed_files_fname)
			&& length_of_file(changed_files_fname) > 2) {
			log_to_screen
				("Warning - unable to check logfile to derive list of changed files");
		} else {
			log_to_screen
				("No differences found. Therefore, no 'changed.files' text file.");
		}
	}
	sprintf(tmp, "cat /tmp/biggies.changed >> %s", changed_files_fname);
	paranoid_system(tmp);

	diffs = count_lines_in_file(changed_files_fname);
	if (diffs > 0) {
		sprintf(tmp, "cp -f %s %s", changed_files_fname,
				"/tmp/changed.files");
		run_program_and_log_output(tmp, FALSE);
		sprintf(tmp,
				"%ld files differed from live filesystem; type less %s or less %s to see",
				diffs, changed_files_fname, "/tmp/changed.files");
		log_msg(0, tmp);
		log_to_screen
			("See /tmp/changed.files for a list of nonmatching files.");
		log_to_screen
			("The files probably changed on filesystem, not on backup media.");
		//      retval++;
	}
	return (retval);
}
Пример #8
0
/*
  =======================================================================================
  =======================================================================================
*/
bool run(HWND hDlg)
{
	char src[MAX_PATH], dst[MAX_PATH], dst_name[MAX_PATH], error[2 * MAX_PATH];
	char *p;
	FILE *fin, *fout;
	int max_particles, line_count;
	bool result;
	
	max_particles = GetDlgItemInt(hDlg, IDC_MAX_PARTICLES, NULL, FALSE);

	if (max_particles == 0) {
		MessageBox(hDlg, "Zero max particles is not acceptable.", "Error", MB_OK);
		return false;
	}

	memset(src, 0, sizeof(src));
	GetDlgItemText(hDlg, IDC_ORIGINAL_LIST, src, MAX_PATH - 1);

	if (!file_exists(src)) {
		return false;
	}

	memset(dst_name, 0, sizeof(dst_name));
	GetDlgItemText(hDlg, IDC_OUTPUT_LIST, dst_name, sizeof(dst_name));

	if (strlen(dst_name) == 0) {
		MessageBox(hDlg, "Need an output file name.", "Error", MB_OK);
		return false;
	}

	strncpy_s(dst, sizeof(dst), src, _TRUNCATE);

	p = strrchr(dst, '\\');

	if (!p) {
		MessageBox(hDlg, "Can't find a path delimiter in the source file!", "Error", MB_OK);
		return false;
	}

	p++;
	*p = 0;
	strncat_s(dst, sizeof(dst), dst_name, _TRUNCATE);

	if (!strcmp(src, dst)) {
		MessageBox(hDlg, "Sorry, not going to overwrite the original list file.", "No Clobbering Originals", MB_OK);
		return false;
	}

	if (file_exists(dst)) {
		sprintf_s(error, sizeof(error), "The output file\n%s\nalready exists.\n\nOverwrite?", dst);

		if (IDNO == MessageBox(hDlg, error, "Overwrite Existing File", MB_YESNO)) {
			return false;
		}
	}
	
	line_count = count_lines_in_file(hDlg, src);

	if (line_count < 0) {
		// error already shown
		return false;
	}
	else if (line_count < 2) {
		MessageBox(hDlg, "Source file line count is too small to believe", "Error", MB_OK);
		return false;
	}

	if (fopen_s(&fin, src, "rb")) {
		MessageBox(hDlg, "Error opening original file.", "Error", MB_OK);
		return false;
	}

	if (fopen_s(&fout, dst, "wb")) {
		fclose(fin);
		MessageBox(hDlg, "Error opening output file.", "Error", MB_OK);
		return false;
	}

	SetCursor(LoadCursor(NULL, IDC_WAIT));

	result = shave(hDlg, line_count, max_particles, fin, fout);
	
	fclose(fin);
	fclose(fout);

	SetCursor(LoadCursor(NULL, IDC_ARROW));

	if (result) {
		p = strrchr(src, '.');

		if (!p) {
			MessageBox(hDlg, "Internal error, source context", "Error Copying Context", MB_OK);
			return false;
		}
		
		*p = 0;
		strncat_s(src, MAX_PATH, ".ctx", _TRUNCATE);

		if (!file_exists(src)) {
			MessageBox(hDlg, "Failed to find context file for original.", "Error Copying Context", MB_OK);
			return false;
		}

		p = strrchr(dst, '.');

		if (!p) {
			MessageBox(hDlg, "Internal error, dest context", "Error Copying Context", MB_OK);
			return false;
		}
			
		*p = 0;
		strncat_s(dst, MAX_PATH, ".ctx", _TRUNCATE);

		if (fopen_s(&fin, src, "rb")) {
			MessageBox(hDlg, "Error opening original context file.", "Error", MB_OK);
			return false;
		}

		if (fopen_s(&fout, dst, "wb")) {
			fclose(fin);
			MessageBox(hDlg, "Error opening output context file.", "Error", MB_OK);
			return false;
		}

		result = copy_context(fin, fout);

		fclose(fin);
		fclose(fout);

		if (!result) {
			MessageBox(hDlg, "Error copying context file.", "Error", MB_OK);
		}

	}

	return result;
}