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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 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.