source: branches/2.06/mondo/mondo/common/libmondo-verify.c @ 296

Last change on this file since 296 was 296, checked in by andree, 15 years ago

Replaced partimagehack with ntfsclone from ntfsprogs package. Replaced
all occurrences of strings 'partimagehack' and 'partimage' with 'ntfsprog'.

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