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

Last change on this file since 688 was 688, checked in by bcornec, 13 years ago

Huge memory management patch.
Still not finished but a lot as been done.
What remains is around some functions returning strings, and some structure members.
(Could not finish due to laptop failure !)

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