source: trunk/mondo/src/common/libmondo-verify.c @ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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