source: MondoRescue/branches/stable/mondo/src/common/libmondo-verify.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

  • Property svn:keywords set to Id
File size: 33.3 KB
Line 
1/* $Id: libmondo-verify.c 1770 2007-11-06 10:01:53Z bruno $ */
2/**
3 * @file
4 * Functions for verifying backups (booted from hard drive, not CD).
5 */
6
7#include <unistd.h>
8
9#include "my-stuff.h"
10#include "mr_mem.h"
11#include "mr_msg.h"
12#include "mr_gettext.h"
13
14#include "mondostructures.h"
15#include "libmondo-verify.h"
16#include "newt-specific-EXT.h"
17#include "libmondo-files-EXT.h"
18#include "libmondo-fork-EXT.h"
19#include "libmondo-stream-EXT.h"
20#include "libmondo-string-EXT.h"
21#include "libmondo-devices-EXT.h"
22#include "libmondo-tools-EXT.h"
23
24/*@unused@*/
25//static char cvsid[] = "$Id: libmondo-verify.c 1770 2007-11-06 10:01:53Z bruno $";
26
27/**
28 * The number of the most recently verified afioball.
29 * @ingroup globalGroup
30 */
31int g_last_afioball_number = -1;
32
33extern char *g_getfacl;
34extern char *g_getfattr;
35extern char *MONDO_LOGFILE;
36
37/* Reference to global bkpinfo */
38extern struct s_bkpinfo *bkpinfo;
39
40
41/**
42 * Generate the filename of a tarball to verify.
43 * @param bkpinfo The backup information structure. @c bkpinfo->compression_suffix is the only field used.
44 * @param mountpoint The directory where the CD/DVD/ISO is mounted.
45 * @param setno The afioball number to get the location of.
46 * @return The absolute path to the afioball.
47 * @note The returned string points to static data that will be overwritten with each call.
48 * @ingroup stringGroup
49 */
50char *vfy_tball_fname(char *mountpoint, int setno)
51{
52 /*@ buffers ******************************************************* */
53 static char output[MAX_STR_LEN];
54
55 assert(bkpinfo != NULL);
56 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
57 sprintf(output, "%s/archives/%d.star.%s", mountpoint, setno,
58 bkpinfo->compression_suffix);
59 if (!does_file_exist(output)) {
60 sprintf(output, "%s/archives/%d.afio.%s", mountpoint, setno,
61 bkpinfo->compression_suffix);
62 }
63 return (output);
64}
65
66
67/**
68 * Generate a list of the files that have changed, based on @c afio @c -r
69 * messages.
70 * @param changedfiles_fname Filename of the place to put a list of afio's reported changed.
71 * @param ignorefiles_fname Filename of a list of files to ignore (use "" if none).
72 * @param stderr_fname File containing afio's stderr output.
73 * @return The number of differences found (0 for a perfect backup).
74 * @bug This function seems orphaned.
75 * @ingroup utilityGroup
76 */
77long
78generate_list_of_changed_files(char *changedfiles_fname,
79 char *ignorefiles_fname, char *stderr_fname)
80{
81 /*@ buffer ********************************************************** */
82 char *command = NULL;
83 char *afio_found_changes = NULL;
84
85 /*@ int ************************************************************* */
86 int res = 0;
87
88 /*@ long ************************************************************ */
89 long afio_diffs = 0;
90
91 assert_string_is_neither_NULL_nor_zerolength(changedfiles_fname);
92 assert_string_is_neither_NULL_nor_zerolength(ignorefiles_fname);
93 assert_string_is_neither_NULL_nor_zerolength(stderr_fname);
94
95 mr_asprintf(&afio_found_changes, "%s.afio", ignorefiles_fname);
96 sync();
97
98
99 mr_msg(1, "Now scanning log file for 'afio: ' stuff");
100 mr_asprintf(&command,
101 "grep \"afio: \" %s | sed 's/afio: //' | grep -vE '^/dev/.*$' >> %s",
102 stderr_fname, afio_found_changes);
103 mr_msg(2, command);
104 res = system(command);
105 mr_free(command);
106 if (res) {
107 mr_msg(2, "Warning - failed to think");
108 }
109
110 mr_msg(1, "Now scanning log file for 'star: ' stuff");
111 mr_asprintf(&command,
112 "grep \"star: \" %s | sed 's/star: //' | grep -vE '^/dev/.*$' >> %s",
113 stderr_fname, afio_found_changes);
114 mr_msg(2, command);
115 res = system(command);
116 mr_free(command);
117 if (res) {
118 mr_msg(2, "Warning - failed to think");
119 }
120// exclude_nonexistent_files (afio_found_changes);
121 afio_diffs = count_lines_in_file(afio_found_changes);
122 mr_asprintf(&command,
123 "sort %s %s %s | uniq -c | awk '{ if ($1==\"2\") {print $2;};}' | grep -v \"incheckentry xwait()\" > %s",
124 ignorefiles_fname, afio_found_changes, afio_found_changes,
125 changedfiles_fname);
126 mr_msg(2, command);
127 paranoid_system(command);
128 mr_free(command);
129 mr_free(afio_found_changes);
130 return (afio_diffs);
131}
132
133
134/**
135 * @addtogroup LLverifyGroup
136 * @{
137 */
138/**
139 * Verify all afioballs stored on the inserted CD (or an ISO image).
140 * @param bkpinfo The backup information structure. @c bkpinfo->backup_media_type
141 * is used in this function, and the structure is also passed to verify_an_afioball_from_CD().
142 * @param mountpoint The location the CD/DVD/ISO is mounted on.
143 * @return The number of sets containing differences (0 for success).
144 */
145int verify_afioballs_on_CD(char *mountpoint)
146{
147
148 /*@ buffers ********************************************************* */
149 char *tmp = NULL;
150
151 /*@ int ************************************************************* */
152 int set_number = 0;
153 int retval = 0;
154 int total_sets = 0;
155 int percentage = 0;
156
157 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
158 assert(bkpinfo != NULL);
159
160 for (set_number = 0;
161 set_number < 9999
162 &&
163 !does_file_exist(vfy_tball_fname(mountpoint, set_number));
164 set_number++);
165 if (!does_file_exist(vfy_tball_fname(mountpoint, set_number))) {
166 return (0);
167 }
168
169 if (g_last_afioball_number != set_number - 1) {
170 if (set_number == 0) {
171 mr_msg(1,
172 "Weird error in verify_afioballs_on_CD() but it's really a cosmetic error, nothing more");
173 } else {
174 retval++;
175 mr_asprintf(&tmp, "Warning - missing set(s) between %d and %d\n",
176 g_last_afioball_number, set_number - 1);
177 log_to_screen(tmp);
178 mr_free(tmp);
179 }
180 }
181 mr_asprintf(&tmp, "Verifying %s #%d's tarballs",
182 bkpinfo->backup_media_string,
183 g_current_media_number);
184 open_evalcall_form(tmp);
185 mr_free(tmp);
186
187 for (total_sets = set_number;
188 does_file_exist(vfy_tball_fname(mountpoint, total_sets));
189 total_sets++) {
190 mr_msg(1, "total_sets = %d", total_sets);
191 }
192 for (;
193 does_file_exist(vfy_tball_fname(mountpoint, set_number));
194 set_number++) {
195 percentage =
196 (set_number - g_last_afioball_number) * 100 / (total_sets -
197 g_last_afioball_number);
198 update_evalcall_form(percentage);
199 mr_msg(1, "set = %d", set_number);
200 retval +=
201 verify_an_afioball_from_CD(vfy_tball_fname(mountpoint, set_number));
202 }
203 g_last_afioball_number = set_number - 1;
204 close_evalcall_form();
205 return (retval);
206}
207
208/**
209 * Verify all slices stored on the inserted CD (or a mounted ISO image).
210 * @param bkpinfo The backup information structure. Fields used:
211 * - @c compression_level
212 * - @c restore_path
213 * - @c compression_suffix
214 * @param mtpt The mountpoint the CD/DVD/ISO is mounted on.
215 * @return The number of differences (0 for perfect biggiefiles).
216 */
217int verify_all_slices_on_CD(char *mtpt)
218{
219
220 /*@ buffer ********************************************************** */
221 char *tmp = NULL;
222 char *tmp2 = NULL;
223 char *mountpoint = NULL;
224 char *command = NULL;
225 static char *bufblkA = NULL;
226 static char *bufblkB = NULL;
227 const long maxbufsize = 65536L;
228 long currsizA = 0L;
229 long currsizB = 0L;
230 long j = 0L;
231 long bigfile_num = 0L;
232 long slice_num = -1;
233 int res = 0;
234
235 static FILE *forig = NULL;
236 static struct s_filename_and_lstat_info biggiestruct;
237 static long last_bigfile_num = -1;
238 static long last_slice_num = -1;
239 FILE *pin = NULL;
240 FILE *fin = NULL;
241 int retval = 0;
242
243 if (!bufblkA) {
244 bufblkA = mr_malloc(maxbufsize);
245 }
246 if (!bufblkB) {
247 bufblkB = mr_malloc(maxbufsize);
248 }
249
250 assert(bkpinfo != NULL);
251 assert_string_is_neither_NULL_nor_zerolength(mtpt);
252
253 iamhere("before vsbf");
254 mr_asprintf(&tmp, "Verifying %s#%d's big files",
255 bkpinfo->backup_media_string,
256 g_current_media_number);
257 open_evalcall_form(tmp);
258 mr_free(tmp);
259
260 iamhere("after vsbf");
261 mr_asprintf(&mountpoint, "%s/archives", mtpt);
262 if (last_bigfile_num == -1) {
263 bigfile_num = 0;
264 slice_num = 0;
265 } else if (slice_num == 0) {
266 bigfile_num = last_bigfile_num + 1;
267 slice_num = 0;
268 } else {
269 bigfile_num = last_bigfile_num;
270 slice_num = last_slice_num + 1;
271 }
272 while (does_file_exist
273 (slice_fname
274 (bigfile_num, slice_num, mountpoint, bkpinfo->compression_suffix))
275 ||
276 does_file_exist(slice_fname
277 (bigfile_num, slice_num, mountpoint, ""))) {
278 // handle slices until end of CD
279 if (slice_num == 0) {
280 mr_msg(2, "ISO=%d bigfile=%ld --START--",
281 g_current_media_number, bigfile_num);
282 if (!
283 (fin =
284 fopen(slice_fname(bigfile_num, slice_num, mountpoint, ""),
285 "r"))) {
286 mr_msg(2, "Cannot open bigfile's info file");
287 } else {
288 if (fread
289 ((void *) &biggiestruct, 1, sizeof(biggiestruct),
290 fin) < sizeof(biggiestruct)) {
291 mr_msg(2, "Unable to get biggiestruct");
292 }
293 paranoid_fclose(fin);
294 }
295 mr_asprintf(&tmp2, "%s/%s", bkpinfo->restore_path,
296 biggiestruct.filename);
297 mr_msg(2, "Opening biggiefile #%ld - '%s'", bigfile_num, tmp2);
298 if (!(forig = fopen(tmp2, "r"))) {
299 mr_msg(2, "Failed to open bigfile. Darn.");
300 log_to_screen(_("%s/%s not found on live filesystem"),
301 bkpinfo->restore_path,
302 biggiestruct.filename);
303 mr_asprintf(&tmp, "echo \"%s/%s not found\" >> %s/biggies.changed",
304 bkpinfo->restore_path,
305 biggiestruct.filename,
306 bkpinfo->tmpdir);
307 system(tmp);
308 mr_free(tmp);
309
310 bigfile_num++;
311 slice_num = 0;
312 retval++;
313 } else {
314 slice_num++;
315 }
316 mr_free(tmp2);
317 } else if (does_file_exist(slice_fname(bigfile_num, slice_num, mountpoint, "")) &&
318 (length_of_file(slice_fname(bigfile_num, slice_num, mountpoint, "")) == 0)) {
319 mr_msg(2, "ISO=%d bigfile=%ld ---END---",
320 g_current_media_number, bigfile_num);
321 bigfile_num++;
322 paranoid_fclose(forig);
323 slice_num = 0;
324 } else {
325 mr_msg(2, "ISO=%d bigfile=%ld slice=%ld",
326 g_current_media_number, bigfile_num, slice_num);
327 if (!does_file_exist(slice_fname(bigfile_num, slice_num, mountpoint, ""))) {
328 mr_asprintf(&command, "%s -dc %s 2>> %s", bkpinfi->compression_tool,
329 slice_fname(bigfile_num, slice_num, mountpoint, bkpinfo->compression_suffix),
330 MONDO_LOGFILE);
331 } else {
332 /* can we set up bkpinfo->compression_level = 0
333 * without needing '-0' on command line?
334 * here and in afio verify */
335 mr_asprintf(&command, "cat %s 2>> %s",
336 slice_fname(bigfile_num, slice_num, mountpoint, ""), MONDO_LOGFILE);
337 }
338 if ((pin = popen(command, "r"))) {
339 res = 0;
340 while (!feof(pin)) {
341 currsizA = fread(bufblkA, 1, maxbufsize, pin);
342 if (currsizA <= 0) {
343 break;
344 }
345 currsizB = fread(bufblkB, 1, currsizA, forig);
346 if (currsizA != currsizB) {
347 res++;
348 } else {
349 for (j = 0;
350 j < currsizA && bufblkA[j] == bufblkB[j];
351 j++);
352 if (j < currsizA) {
353 res++;
354 }
355 }
356 }
357 paranoid_pclose(pin);
358 if (res && !strncmp(biggiestruct.filename, "/dev/", 5)) {
359 mr_msg(3,
360 "Ignoring differences between %s and live filesystem because it's a device and therefore the archives are stored via ntfsclone, not dd.",
361 biggiestruct.filename);
362 mr_msg(3,
363 "If you really want verification for %s, please contact the devteam and offer an incentive.",
364 biggiestruct.filename);
365 res = 0;
366 }
367 if (res) {
368 mr_msg(0,
369 "afio: \"%s\": Corrupt biggie file, says libmondo-archive.c",
370 biggiestruct.filename);
371 retval++;
372 }
373 }
374 mr_free(command);
375 slice_num++;
376 }
377 }
378 mr_free(tmp);
379 mr_free(mountpoint);
380
381 last_bigfile_num = bigfile_num;
382 last_slice_num = slice_num - 1;
383 if (last_slice_num < 0) {
384 last_bigfile_num--;
385 }
386 close_evalcall_form();
387 if (bufblkA) {
388 mr_free(bufblkA);
389 }
390 if (bufblkB) {
391 mr_free(bufblkB);
392 }
393 return (0);
394}
395
396
397/**
398 * Verify one afioball from the CD.
399 * You should be changed to the root directory (/) for this to work.
400 * @param bkpinfo The backup information structure. Fields used:
401 * - @c bkpinfo->tmpdir
402 * - @c bkpinfo->compression_tool
403 * - @c bkpinfo->compression_suffix
404 * @param tarball_fname The filename of the afioball to verify.
405 * @return 0, always.
406 */
407int verify_a_tarball(char *tarball_fname)
408{
409 /*@ buffers ********************************************************* */
410 char *command = NULL;
411 char *outlog = NULL;
412 char *tmp = NULL;
413
414 /*@ pointers ******************************************************* */
415 FILE *pin = NULL;
416
417 size_t n = 0;
418
419 /*@ long *********************************************************** */
420 long diffs = 0;
421
422 assert(bkpinfo != NULL);
423 assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
424
425 log_it("Verifying fileset '%s'", tarball_fname);
426
427 mr_asprintf(&outlog, "%s/afio.log", bkpinfo->tmpdir);
428 unlink(outlog);
429
430 if (strstr(tarball_fname, ".star")) {
431 bkpinfo->use_star = TRUE;
432 if (strstr(tarball_fname, ".bz2")) {
433 mr_asprintf(&command,
434 "star -diff diffopts=mode,size,data file=%s %s >> %s 2>> %s",
435 tarball_fname,
436 (strstr(tarball_fname, ".bz2")) ? "-bz" : " ", outlog,
437 outlog);
438 } else {
439 mr_asprintf(&command,"");
440 }
441 } else {
442 bkpinfo->use_star = FALSE;
443 mr_asprintf(&command, "afio -r -P %s -Z %s >> %s 2>> %s",
444 bkpinfo->compression_tool, tarball_fname, outlog, outlog);
445 }
446 mr_msg(6, "command=%s", command);
447 paranoid_system(command);
448 mr_free(command);
449
450 if (length_of_file(outlog) < 10) {
451 /* BERLIOS: This seems useless !! */
452 mr_asprintf(&command, "cat %s >> %s", outlog, MONDO_LOGFILE);
453 } else {
454 mr_asprintf(&command, "cut -d':' -f%d %s | sort -u",
455 (bkpinfo->use_star) ? 1 : 2, outlog);
456 pin = popen(command, "r");
457 if (pin) {
458 for (mr_getline(&tmp, &n, pin); !feof(pin);
459 mr_getline(&tmp, &n, pin)) {
460 if (bkpinfo->use_star) {
461 if (!strstr(tmp, "diffopts=")) {
462 while (strlen(tmp) > 0
463 && tmp[strlen(tmp) - 1] < 32) {
464 tmp[strlen(tmp) - 1] = '\0';
465 }
466 if (strchr(tmp, '/')) {
467 if (!diffs) {
468 mr_msg(0, "'%s' - differences found",
469 tarball_fname);
470 }
471 mr_msg(0, "star: /%s",
472 strip_afio_output_line(tmp));
473 diffs++;
474 }
475 }
476 } else {
477 if (!diffs) {
478 mr_msg(0, "'%s' - differences found",
479 tarball_fname);
480 }
481 mr_msg(0, "afio: /%s", strip_afio_output_line(tmp));
482 diffs++;
483 }
484 }
485 paranoid_pclose(pin);
486 mr_free(tmp);
487 } else {
488 log_OS_error(command);
489 }
490 }
491 mr_free(outlog);
492 mr_free(command);
493
494 return (0);
495}
496
497
498/**
499 * Verify one afioball from the CD.
500 * Checks for existence (calls fatal_error() if it does not exist) and
501 * then calls verify_an_afioball().
502 * @param bkpinfo The backup information structure. Passed to verify_an_afioball().
503 * @param tarball_fname The filename of the afioball to verify.
504 * @return The return value of verify_an_afioball().
505 * @see verify_an_afioball
506 */
507int
508verify_an_afioball_from_CD(char *tarball_fname)
509{
510
511 /*@ int ************************************************************* */
512 int res = 0;
513
514 assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
515
516 mr_msg(1, "Verifying %s", tarball_fname);
517 if (!does_file_exist(tarball_fname)) {
518 fatal_error("Cannot verify nonexistent afioball");
519 }
520 res = verify_a_tarball(tarball_fname);
521 return (res);
522}
523
524
525/**
526 * Verify one afioball from the opened tape/CD stream.
527 * Copies the file from tape to tmpdir and then calls verify_an_afioball().
528 * @param bkpinfo The backup information structure. Passed to verify_an_afioball().
529 * @param orig_fname The original filename of the afioball to verify.
530 * @param size The size of the afioball to verify.
531 * @return The return value of verify_an_afioball().
532 * @see verify_an_afioball
533 */
534int
535verify_an_afioball_from_stream(char *orig_fname, long long size)
536{
537
538 /*@ int ************************************************************** */
539 int retval = 0;
540 int res = 0;
541
542 /*@ buffers ********************************************************** */
543 char *tmp = NULL;
544 char *tarball_fname = NULL;
545
546 /*@ pointers ********************************************************* */
547 char *p = NULL;
548
549 assert(bkpinfo != NULL);
550 assert_string_is_neither_NULL_nor_zerolength(orig_fname);
551
552 p = strrchr(orig_fname, '/');
553 if (!p) {
554 p = orig_fname;
555 } else {
556 p++;
557 }
558 mr_asprintf(&tmp, "mkdir -p %s/tmpfs", bkpinfo->tmpdir);
559 paranoid_system(tmp);
560 mr_free(tmp);
561
562 mr_asprintf(&tarball_fname, "%s/tmpfs/temporary-%s", bkpinfo->tmpdir, p);
563 read_file_from_stream_to_file(tarball_fname, size);
564 res = verify_a_tarball(tarball_fname);
565 if (res) {
566 mr_msg(0, "Afioball '%s' no longer matches your live filesystem", p);
567 retval++;
568 }
569 unlink(tarball_fname);
570 mr_free(tarball_fname);
571 return (retval);
572}
573
574
575/**
576 * Verify one biggiefile form the opened tape/CD stream.
577 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir is the only field used.
578 * @param biggie_fname The filename of the biggiefile to verify.
579 * @param size The size in bytes of said biggiefile.
580 * @return 0 for success (even if the file doesn't match); nonzero for a tape error.
581 */
582int
583verify_a_biggiefile_from_stream(char *biggie_fname, long long size)
584{
585
586 /*@ int ************************************************************* */
587 int retval = 0;
588 int res = 0;
589 int current_slice_number = 0;
590 int ctrl_chr = '\0';
591
592 /*@ char ************************************************************ */
593 char *test_file = NULL;
594 char *biggie_cksum = NULL;
595 char *orig_cksum = NULL;
596 char *tmp = NULL;
597 char *slice_fnam = NULL;
598
599 /*@ pointers ******************************************************** */
600 char *p;
601
602 /*@ long long ******************************************************* */
603 long long slice_siz;
604
605 malloc_string(slice_fnam);
606 assert(bkpinfo != NULL);
607 assert_string_is_neither_NULL_nor_zerolength(biggie_fname);
608
609 p = strrchr(biggie_fname, '/');
610 if (!p) {
611 p = biggie_fname;
612 } else {
613 p++;
614 }
615 mr_asprintf(&test_file, "%s/temporary-%s", bkpinfo->tmpdir, p);
616 for (res =
617 read_header_block_from_stream(&slice_siz, slice_fnam, &ctrl_chr);
618 ctrl_chr != BLK_STOP_A_BIGGIE;
619 res =
620 read_header_block_from_stream(&slice_siz, slice_fnam,
621 &ctrl_chr)) {
622 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
623 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
624 }
625 res = read_file_from_stream_to_file(test_file, slice_siz);
626 unlink(test_file);
627 res =
628 read_header_block_from_stream(&slice_siz, slice_fnam,
629 &ctrl_chr);
630 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
631 mr_msg(2, "test_file = %s", test_file);
632 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
633 }
634 current_slice_number++;
635 retval += res;
636 }
637 mr_free(test_file);
638
639 mr_asprintf(&biggie_cksum, slice_fnam);
640 mr_free(slice_fnam);
641
642 if (biggie_cksum[0] != '\0') {
643 mr_asprintf(&orig_cksum, calc_checksum_of_file(biggie_fname));
644 if (strcmp(biggie_cksum, orig_cksum)) {
645 mr_asprintf(&tmp, "orig cksum=%s; curr cksum=%s", biggie_cksum,
646 orig_cksum);
647 mr_msg(2, tmp);
648 mr_free(tmp);
649
650 mr_asprintf(&tmp, _("%s has changed on live filesystem"),
651 biggie_fname);
652 log_to_screen(tmp);
653 mr_free(tmp);
654
655 mr_asprintf(&tmp, "echo \"%s\" >> %s/biggies.changed",
656 biggie_fname, bkpinfo->tmpdir);
657 system(tmp);
658 mr_free(tmp);
659 }
660 mr_free(orig_cksum);
661 }
662 mr_free(biggie_cksum);
663 return (retval);
664}
665
666
667/**
668 * Verify all afioballs from the opened tape/CD stream.
669 * @param bkpinfo The backup information structure. Fields used:
670 * - @c bkpinfo->restore_path
671 * - @c bkpinfo->tmpdir
672 *
673 * @return 0 for success (even if there are differences); nonzero for a tape error.
674 */
675int verify_afioballs_from_stream()
676{
677 /*@ int ********************************************************** */
678 int retval = 0;
679 int res = 0;
680 long current_afioball_number = 0;
681 int ctrl_chr = 0;
682 int total_afioballs = 0;
683
684 /*@ buffers ***************************************************** */
685 char *tmp = NULL;
686 char *fname = NULL;
687 char *curr_xattr_list_fname = NULL;
688 char *curr_acl_list_fname = NULL;
689
690 /*@ long long *************************************************** */
691 long long size = 0;
692
693 assert(bkpinfo != NULL);
694 malloc_string(fname);
695
696 if (g_getfattr) {
697 mr_asprintf(&curr_xattr_list_fname, XATTR_BIGGLST_FNAME_RAW_SZ,
698 bkpinfo->tmpdir);
699 }
700 if (g_getfacl) {
701 mr_asprintf(&curr_acl_list_fname, ACL_BIGGLST_FNAME_RAW_SZ,
702 bkpinfo->tmpdir);
703 }
704 log_to_screen(_("Verifying regular archives on tape"));
705 total_afioballs = get_last_filelist_number() + 1;
706 open_progress_form(_("Verifying filesystem"),
707 _("I am verifying archives against your live filesystem now."),
708 _("Please wait. This may take a couple of hours."), "",
709 total_afioballs);
710 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
711 if (ctrl_chr != BLK_START_AFIOBALLS) {
712 iamhere("YOU SHOULD NOT GET HERE");
713 iamhere("Grabbing the EXAT files");
714 if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
715 res =
716 read_EXAT_files_from_tape(&size, fname, &ctrl_chr,
717 curr_xattr_list_fname,
718 curr_acl_list_fname);
719 }
720 }
721 if (ctrl_chr != BLK_START_AFIOBALLS) {
722 wrong_marker(BLK_START_AFIOBALLS, ctrl_chr);
723 }
724 mr_free(curr_xattr_list_fname);
725 mr_free(curr_acl_list_fname);
726
727 for (res = read_header_block_from_stream(&size, fname, &ctrl_chr);
728 ctrl_chr != BLK_STOP_AFIOBALLS;
729 res = read_header_block_from_stream(&size, fname, &ctrl_chr)) {
730 if (g_getfattr) {
731 mr_asprintf(&curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
732 bkpinfo->tmpdir, current_afioball_number);
733 }
734 if (g_getfacl) {
735 mr_asprintf(&curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
736 bkpinfo->tmpdir, current_afioball_number);
737 }
738 if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
739 iamhere("Reading EXAT files from tape");
740 res =
741 read_EXAT_files_from_tape(&size, fname, &ctrl_chr,
742 curr_xattr_list_fname,
743 curr_acl_list_fname);
744 }
745 mr_free(curr_xattr_list_fname);
746 mr_free(curr_acl_list_fname);
747
748 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
749 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
750 }
751 mr_asprintf(&tmp, "Verifying fileset #%ld", current_afioball_number);
752 update_progress_form(tmp);
753 mr_free(tmp);
754
755 res = verify_an_afioball_from_stream(fname, size);
756 if (res) {
757 mr_asprintf(&tmp, _("Afioball %ld differs from live filesystem"),
758 current_afioball_number);
759 log_to_screen(tmp);
760 mr_free(tmp);
761 }
762 retval += res;
763 current_afioball_number++;
764 g_current_progress++;
765 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
766 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
767 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
768 }
769 }
770 mr_msg(1, "All done with afioballs");
771 close_progress_form();
772 mr_free(fname);
773 return (retval);
774}
775
776/**
777 * Verify all biggiefiles on the opened CD/tape stream.
778 * @param bkpinfo The backup information structure. Fields used:
779 * - @c bkpinfo->restore_path
780 * - @c bkpinfo->tmpdir
781 *
782 * @return 0 for success (even if there are differences); nonzero for a tape error.
783 */
784int verify_biggiefiles_from_stream()
785{
786
787 /*@ int ************************************************************ */
788 int retval = 0;
789 int res = 0;
790 int ctrl_chr = 0;
791
792 /*@ long *********************************************************** */
793 long noof_biggiefiles = 0;
794 long current_biggiefile_number = 0;
795
796 /*@ buffers ******************************************************** */
797 char *orig_fname = NULL;
798 char *logical_fname = NULL;
799 char *comment = NULL;
800 char *curr_xattr_list_fname = NULL;
801 char *curr_acl_list_fname = NULL;
802 /*@ pointers ******************************************************* */
803 char *p = NULL;
804
805 /*@ long long size ************************************************* */
806 long long size = 0;
807
808 assert(bkpinfo != NULL);
809 malloc_string(orig_fname);
810
811 if (g_getfattr) {
812 mr_asprintf(&curr_xattr_list_fname, XATTR_BIGGLST_FNAME_RAW_SZ,
813 bkpinfo->tmpdir);
814 }
815 if (g_getfacl) {
816 mr_asprintf(&curr_acl_list_fname, ACL_BIGGLST_FNAME_RAW_SZ,
817 bkpinfo->tmpdir);
818 }
819 mr_asprintf(&comment, "Verifying all bigfiles.");
820 log_to_screen(comment);
821 res = read_header_block_from_stream(&size, orig_fname, &ctrl_chr);
822 if (ctrl_chr != BLK_START_BIGGIEFILES) {
823 if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
824 iamhere("Grabbing the EXAT biggiefiles");
825 res =
826 read_EXAT_files_from_tape(&size, orig_fname,
827 &ctrl_chr, curr_xattr_list_fname,
828 curr_acl_list_fname);
829 }
830 }
831 mr_free(curr_xattr_list_fname);
832 mr_free(curr_acl_list_fname);
833
834 if (ctrl_chr != BLK_START_BIGGIEFILES) {
835 wrong_marker(BLK_START_BIGGIEFILES, ctrl_chr);
836 }
837 noof_biggiefiles = (long) size;
838 mr_msg(1, "noof_biggiefiles = %ld", noof_biggiefiles);
839 open_progress_form(_("Verifying big files"), comment,
840 _("Please wait. This may take some time."), "",
841 noof_biggiefiles);
842 mr_free(comment);
843
844 for (res = read_header_block_from_stream(&size, orig_fname, &ctrl_chr);
845 ctrl_chr != BLK_STOP_BIGGIEFILES;
846 res = read_header_block_from_stream(&size, orig_fname, &ctrl_chr))
847 {
848 if (ctrl_chr != BLK_START_A_NORMBIGGIE
849 && ctrl_chr != BLK_START_A_PIHBIGGIE) {
850 wrong_marker(BLK_START_A_NORMBIGGIE, ctrl_chr);
851 }
852 p = strrchr(orig_fname, '/');
853 if (!p) {
854 p = orig_fname;
855 } else {
856 p++;
857 }
858 mr_asprintf(&comment, _("Verifying bigfile #%ld (%ld K)"),
859 current_biggiefile_number, (long) size >> 10);
860 update_progress_form(comment);
861 mr_free(comment);
862
863 mr_asprintf(&logical_fname, "%s/%s", bkpinfo->restore_path,
864 orig_fname);
865 res =
866 verify_a_biggiefile_from_stream(logical_fname, size);
867 mr_free(logical_fname);
868 retval += res;
869 current_biggiefile_number++;
870 g_current_progress++;
871 }
872 close_progress_form();
873 mr_free(orig_fname);
874 return (retval);
875}
876
877/* @} - end of LLverifyGroup */
878
879
880/**
881 * Verify the USB device
882 * @param bkpinfo The backup information structure. Fields used:
883 * - @c bkpinfo->isodir
884 * - @c bkpinfo->media_device
885 * - @c bkpinfo->tmpdir
886 * - @c bkpinfo->verify_data
887 *
888 * @return 0 for success (even if differences are found), nonzero for failure.
889 * @ingroup verifyGroup
890 */
891int verify_usb_image()
892{
893
894 /*@ int ************************************************************ */
895 int retval = 0;
896
897 /*@ buffers ******************************************************** */
898 char *mountpoint = NULL;
899 char *tmp = NULL;
900 char *tmp1 = NULL;
901 char *fname = NULL;
902 int ret = 0;
903#ifdef __FreeBSD__
904 char mdd[32];
905 char *mddevice = mdd;
906 int vndev = 2;
907#else
908//skip
909#endif
910
911 assert(bkpinfo != NULL);
912
913 asprintf(&fname, "%s1", bkpinfo->media_device);
914 if (is_this_device_mounted(fname)) {
915 log_msg(1, "USB device mounted. Remounting it at the right place");
916 asprintf(&tmp, "umount %s", fname);
917 run_program_and_log_output(tmp, FALSE);
918 paranoid_free(tmp);
919 }
920 paranoid_free(fname);
921
922 log_msg(1, "Mounting USB device.");
923 asprintf(&mountpoint, "%s/usb", bkpinfo->tmpdir);
924 asprintf(&tmp, "mkdir -p %s", mountpoint);
925 run_program_and_log_output(tmp, FALSE);
926 paranoid_free(tmp);
927 /* Mindi always create one single parition on the USB dev */
928 asprintf(&tmp, "mount %s1 %s", bkpinfo->media_device, mountpoint);
929 ret = run_program_and_log_output(tmp, FALSE);
930 paranoid_free(tmp);
931 if (ret) {
932 paranoid_free(mountpoint);
933 return(ret);
934 }
935
936 sync();
937 log_msg(2, "OK, I've mounted the USB Disk/Key\n");
938 asprintf(&tmp, "%s/archives/NOT-THE-LAST", mountpoint);
939 if (!does_file_exist(tmp)) {
940 log_msg
941 (2,
942 "This is the last USB device. I am therefore setting bkpinfo->verify_data to FALSE.");
943 bkpinfo->verify_data = FALSE;
944/*
945 (a) It's an easy way to tell the calling subroutine that we've finished &
946 there are no more device to be verified; (b) It stops the post-backup verifier
947 from running after the per-device verifier has run too.
948*/
949 }
950 paranoid_free(tmp);
951 verify_afioballs_on_CD(mountpoint);
952 iamhere("before verify_all_slices");
953 verify_all_slices_on_CD(mountpoint);
954
955 asprintf(&tmp1, "umount %s", mountpoint);
956#ifdef __FreeBSD__
957 ret += system(tmp1);
958 ret += kick_vn(mddevice);
959 if (ret)
960#else
961 if (system(tmp1))
962#endif
963 {
964 asprintf(&tmp, "%s failed; unable to unmount USB device\n", tmp1);
965 log_to_screen(tmp);
966 paranoid_free(tmp);
967 retval++;
968 } else {
969 log_msg(2, "OK, I've unmounted the USB device\n");
970 }
971 paranoid_free(tmp1);
972 paranoid_free(mountpoint);
973 return (retval);
974}
975
976
977/**
978 * Verify the CD indicated by @c g_current_media_number.
979 * @param bkpinfo The backup information structure. Fields used:
980 * - @c bkpinfo->isodir
981 * - @c bkpinfo->prefix
982 * - @c bkpinfo->manual_tray
983 * - @c bkpinfo->media_device
984 * - @c bkpinfo->nfs_remote_dir
985 * - @c bkpinfo->tmpdir
986 * - @c bkpinfo->verify_data
987 *
988 * @return 0 for success (even if differences are found), nonzero for failure.
989 * @ingroup verifyGroup
990 */
991int verify_cd_image()
992{
993
994 /*@ int ************************************************************ */
995 int retval = 0;
996
997 /*@ buffers ******************************************************** */
998 char *mountpoint = NULL;
999 char *command = NULL;
1000 char *tmp = NULL;
1001 char *fname = NULL;
1002#ifdef __FreeBSD__
1003 char mdd[32];
1004 char *mddevice = mdd;
1005 int ret = 0;
1006 int vndev = 2;
1007#else
1008//skip
1009#endif
1010
1011 assert(bkpinfo != NULL);
1012
1013 mr_asprintf(&mountpoint, "%s/cdrom", bkpinfo->tmpdir);
1014 mr_asprintf(&fname, "%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->nfs_remote_dir,
1015 bkpinfo->prefix, g_current_media_number);
1016
1017 mkdir(mountpoint, 1777);
1018 sync();
1019 if (!does_file_exist(fname)) {
1020 mr_asprintf(&tmp,
1021 "%s not found; assuming you backed up to CD; verifying CD...",
1022 fname);
1023 mr_msg(2, tmp);
1024 mr_free(tmp);
1025
1026 if (bkpinfo->manual_tray) {
1027 popup_and_OK(_("Please push CD tray closed."));
1028 }
1029 if (find_and_mount_actual_cd(mountpoint)) {
1030 log_to_screen(_("failed to mount actual CD"));
1031 return (1);
1032 }
1033 } else {
1034 mr_asprintf(&tmp, "%s found; verifying ISO...", fname);
1035 log_to_screen(tmp);
1036 mr_free(tmp);
1037#ifdef __FreeBSD__
1038 ret = 0;
1039 vndev = 2;
1040 mddevice = make_vn(fname);
1041 if (ret) {
1042 mr_asprintf(&tmp, _("make_vn of %s failed; unable to verify ISO\n"),
1043 fname);
1044 log_to_screen(tmp);
1045 mr_free(tmp);
1046 return (1);
1047 }
1048 mr_asprintf(&command, "mount_cd9660 %s %s", mddevice, mountpoint);
1049#else
1050 mr_asprintf(&command, "mount -o loop,ro -t iso9660 %s %s", fname,
1051 mountpoint);
1052#endif
1053 if (run_program_and_log_output(command, FALSE)) {
1054 mr_asprintf(&tmp, _("%s failed; unable to mount ISO image\n"),
1055 command);
1056 log_to_screen(tmp);
1057 mr_free(tmp);
1058 mr_free(command);
1059 return (1);
1060 }
1061 mr_free(command);
1062 }
1063 mr_msg(2, "OK, I've mounted the ISO/CD\n");
1064 mr_asprintf(&tmp, "%s/archives/NOT-THE-LAST", mountpoint);
1065 if (!does_file_exist(tmp)) {
1066 mr_msg
1067 (2,
1068 "This is the last CD. I am therefore setting bkpinfo->verify_data to FALSE.");
1069 bkpinfo->verify_data = FALSE;
1070/*
1071 (a) It's an easy way to tell the calling subroutine that we've finished &
1072 there are no more CD's to be verified; (b) It stops the post-backup verifier
1073 from running after the per-CD verifier has run too.
1074*/
1075 }
1076 mr_free(tmp);
1077
1078 verify_afioballs_on_CD(mountpoint);
1079 iamhere("before verify_all_slices");
1080 verify_all_slices_on_CD(mountpoint);
1081
1082 mr_asprintf(&command, "umount %s", mountpoint);
1083#ifdef __FreeBSD__
1084 ret = 0;
1085 ret += system(command);
1086 ret += kick_vn(mddevice);
1087 if (ret)
1088#else
1089 if (system(command))
1090#endif
1091 {
1092 mr_asprintf(&tmp, "%s failed; unable to unmount ISO image\n",
1093 command);
1094 log_to_screen(tmp);
1095 mr_free(tmp);
1096 retval++;
1097 } else {
1098 mr_msg(2, "OK, I've unmounted the ISO file\n");
1099 }
1100 mr_free(command);
1101 mr_free(mountpoint);
1102
1103 if (!does_file_exist(fname)) {
1104 mr_asprintf(&command, "umount %s", bkpinfo->media_device);
1105 run_program_and_log_output(command, 2);
1106 mr_free(command);
1107
1108 if (!bkpinfo->please_dont_eject
1109 && eject_device(bkpinfo->media_device)) {
1110 mr_msg(2, "Failed to eject CD-ROM drive");
1111 }
1112 }
1113 mr_free(fname);
1114 return (retval);
1115}
1116
1117
1118/**
1119 * Verify all backups on tape.
1120 * This should be done after the backup process has already closed the tape.
1121 * @param bkpinfo The backup information structure. Passed to various helper functions.
1122 * @return 0 for success (even if thee were differences), nonzero for failure.
1123 * @ingroup verifyGroup
1124 */
1125int verify_tape_backups()
1126{
1127
1128 /*@ int ************************************************************ */
1129 int retval = 0;
1130
1131 /*@ buffers ******************************************************** */
1132 char *tmp = NULL;
1133 char *changed_files_fname = NULL;
1134
1135 /*@ long *********************************************************** */
1136 long diffs = 0;
1137
1138 assert(bkpinfo != NULL);
1139
1140 mr_msg(3, "verify_tape_backups --- starting");
1141 log_to_screen(_("Verifying backups"));
1142 openin_tape();
1143
1144 /* verify archives themselves */
1145 retval += verify_afioballs_from_stream();
1146 retval += verify_biggiefiles_from_stream();
1147
1148 /* find the final blocks */
1149 sync();
1150 sleep(2);
1151 closein_tape();
1152
1153 /* close tape; exit */
1154 mr_asprintf(&tmp,"rm -f %s/biggies.changed %s/changed.files 2> /dev/null", bkpinfo->tmpdir, bkpinfo->tmpdir);
1155 paranoid_system(tmp);
1156 mr_free(tmp);
1157
1158 mr_asprintf(&changed_files_fname, "%s/changed.files", bkpinfo->tmpdir);
1159 mr_asprintf(&tmp,
1160 "grep -E '^%s:.*$' %s | cut -d'\"' -f2 | sort -u | awk '{print \"/\"$0;};' | tr -s '/' '/' | grep -v \"(total of\" | grep -v \"incheckentry.*xwait\" | grep -vE '^/afio:.*$' | grep -vE '^dev/.*$' > %s",
1161 (bkpinfo->use_star) ? "star" : "afio", MONDO_LOGFILE,
1162 changed_files_fname);
1163 mr_msg(2, "Running command to derive list of changed files");
1164 mr_msg(2, tmp);
1165 if (system(tmp)) {
1166 if (does_file_exist(changed_files_fname)
1167 && length_of_file(changed_files_fname) > 2) {
1168 log_to_screen
1169 (_("Warning - unable to check logfile to derive list of changed files"));
1170 } else {
1171 log_to_screen
1172 (_("No differences found. Therefore, no 'changed.files' text file."));
1173 }
1174 }
1175 mr_free(tmp);
1176
1177 mr_asprintf(&tmp, "cat %s/biggies.changed >> %s", bkpinfo->tmpdir, changed_files_fname);
1178 paranoid_system(tmp);
1179 mr_free(tmp);
1180
1181 diffs = count_lines_in_file(changed_files_fname);
1182 if (diffs > 0) {
1183 mr_asprintf(&tmp, "cp -f %s %s/changed.files", changed_files_fname, MONDO_CACHE);
1184 run_program_and_log_output(tmp, FALSE);
1185 mr_free(tmp);
1186
1187 mr_asprintf(&tmp,
1188 "%ld files differed from live filesystem; type less %s or less %s/changed.files to see",
1189 diffs, changed_files_fname, MONDO_CACHE);
1190 mr_msg(0, tmp);
1191 mr_free(tmp);
1192
1193 log_to_screen
1194 (_("See "MONDO_CACHE"/changed.files for a list of nonmatching files."));
1195 log_to_screen
1196 (_("The files probably changed on filesystem, not on backup media."));
1197 }
1198 mr_free(changed_files_fname);
1199 return (retval);
1200}
1201
1202
Note: See TracBrowser for help on using the repository browser.