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

Last change on this file since 1185 was 1185, checked in by Bruno Cornec, 17 years ago

Merges in trunk modifications coming from stable (common)

  • Property svn:keywords set to Id
File size: 31.9 KB
Line 
1/* $Id: libmondo-verify.c 1185 2007-02-19 00:51:26Z bruno $ */
2/**
3 * @file
4 * Functions for verifying backups (booted from hard drive, not CD).
5 */
6
7#include <unistd.h>
8
9#include "my-stuff.h"
10#include "mr_mem.h"
11#include "mr_msg.h"
12
13#include "mondostructures.h"
14#include "libmondo-verify.h"
15#include "newt-specific-EXT.h"
16#include "libmondo-files-EXT.h"
17#include "libmondo-fork-EXT.h"
18#include "libmondo-stream-EXT.h"
19#include "libmondo-string-EXT.h"
20#include "libmondo-devices-EXT.h"
21#include "libmondo-tools-EXT.h"
22
23/*@unused@*/
24//static char cvsid[] = "$Id: libmondo-verify.c 1185 2007-02-19 00:51:26Z bruno $";
25
26char *vfy_tball_fname(struct s_bkpinfo *, char *, int);
27
28
29/**
30 * The number of the most recently verified afioball.
31 * @ingroup globalGroup
32 */
33int g_last_afioball_number = -1;
34
35extern char *g_getfacl;
36extern char *g_getfattr;
37
38/**
39 * Generate a list of the files that have changed, based on @c afio @c -r
40 * messages.
41 * @param changedfiles_fname Filename of the place to put a list of afio's reported changed.
42 * @param ignorefiles_fname Filename of a list of files to ignore (use "" if none).
43 * @param stderr_fname File containing afio's stderr output.
44 * @return The number of differences found (0 for a perfect backup).
45 * @bug This function seems orphaned.
46 * @ingroup utilityGroup
47 */
48long
49generate_list_of_changed_files(char *changedfiles_fname,
50 char *ignorefiles_fname, char *stderr_fname)
51{
52 /*@ buffer ********************************************************** */
53 char *command = NULL;
54 char *afio_found_changes = NULL;
55
56 /*@ int ************************************************************* */
57 int res = 0;
58
59 /*@ long ************************************************************ */
60 long afio_diffs = 0;
61
62 assert_string_is_neither_NULL_nor_zerolength(changedfiles_fname);
63 assert_string_is_neither_NULL_nor_zerolength(ignorefiles_fname);
64 assert_string_is_neither_NULL_nor_zerolength(stderr_fname);
65
66 mr_asprintf(&afio_found_changes, "%s.afio", ignorefiles_fname);
67 sync();
68
69
70 mr_msg(1, "Now scanning log file for 'afio: ' stuff");
71 mr_asprintf(&command,
72 "grep \"afio: \" %s | sed 's/afio: //' | grep -vE '^/dev/.*$' >> %s",
73 stderr_fname, afio_found_changes);
74 mr_msg(2, command);
75 res = system(command);
76 mr_free(command);
77 if (res) {
78 mr_msg(2, "Warning - failed to think");
79 }
80
81 mr_msg(1, "Now scanning log file for 'star: ' stuff");
82 mr_asprintf(&command,
83 "grep \"star: \" %s | sed 's/star: //' | grep -vE '^/dev/.*$' >> %s",
84 stderr_fname, afio_found_changes);
85 mr_msg(2, command);
86 res = system(command);
87 mr_free(command);
88 if (res) {
89 mr_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 mr_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 mr_msg(2, command);
98 paranoid_system(command);
99 mr_free(command);
100 mr_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 mr_msg(1,
144 "Weird error in verify_afioballs_on_CD() but it's really a cosmetic error, nothing more");
145 } else {
146 retval++;
147 mr_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 mr_free(tmp);
151 }
152 }
153 mr_asprintf(&tmp, "Verifying %s #%d's tarballs",
154 bkpinfo->backup_media_string,
155 g_current_media_number);
156 open_evalcall_form(tmp);
157 mr_free(tmp);
158
159 for (total_sets = set_number;
160 does_file_exist(vfy_tball_fname(bkpinfo, mountpoint, total_sets));
161 total_sets++) {
162 mr_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 mr_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 * Verify all slices stored on the inserted CD (or a mounted ISO image).
184 * @param bkpinfo The backup information structure. Fields used:
185 * - @c compression_level
186 * - @c restore_path
187 * - @c use_lzo
188 * - @c zip_suffix
189 * @param mtpt The mountpoint the CD/DVD/ISO is mounted on.
190 * @return The number of differences (0 for perfect biggiefiles).
191 */
192int verify_all_slices_on_CD(struct s_bkpinfo *bkpinfo, char *mtpt)
193{
194
195 /*@ buffer ********************************************************** */
196 char *tmp = NULL;
197 char *tmp1 = NULL;
198 char *tmp2 = NULL;
199 char *mountpoint = NULL;
200 char *command = NULL;
201 char *sz_exe = NULL;
202 static char *bufblkA = NULL;
203 static char *bufblkB = NULL;
204 const long maxbufsize = 65536L;
205 long currsizA = 0L;
206 long currsizB = 0L;
207 long j = 0L;
208 long bigfile_num = 0L;
209 long slice_num = -1;
210 int res = 0;
211
212 static FILE *forig = NULL;
213 static struct s_filename_and_lstat_info biggiestruct;
214 static long last_bigfile_num = -1;
215 static long last_slice_num = -1;
216 FILE *pin = NULL;
217 FILE *fin = NULL;
218 int retval = 0;
219
220 if (!bufblkA) {
221 bufblkA = mr_malloc(maxbufsize);
222 }
223 if (!bufblkB) {
224 bufblkB = mr_malloc(maxbufsize);
225 }
226
227 assert(bkpinfo != NULL);
228 assert_string_is_neither_NULL_nor_zerolength(mtpt);
229
230 if (bkpinfo->compression_level > 0) {
231 if (bkpinfo->use_lzo) {
232 mr_asprintf(&sz_exe, "lzop");
233 } else if (bkpinfo->use_gzip) {
234 mr_asprintf(&sz_exe, "gzip");
235 } else {
236 mr_asprintf(&sz_exe, "bzip2");
237 }
238 } else {
239 mr_asprintf(&sz_exe, "");
240 }
241
242 iamhere("before vsbf");
243 mr_asprintf(&tmp, "Verifying %s#%d's big files",
244 bkpinfo->backup_media_string,
245 g_current_media_number);
246 open_evalcall_form(tmp);
247 mr_free(tmp);
248
249 iamhere("after vsbf");
250 mr_asprintf(&mountpoint, "%s/archives", mtpt);
251 if (last_bigfile_num == -1) {
252 bigfile_num = 0;
253 slice_num = 0;
254 } else if (slice_num == 0) {
255 bigfile_num = last_bigfile_num + 1;
256 slice_num = 0;
257 } else {
258 bigfile_num = last_bigfile_num;
259 slice_num = last_slice_num + 1;
260 }
261
262 tmp = slice_fname(bigfile_num, slice_num, mountpoint, bkpinfo->zip_suffix);
263 tmp1 = slice_fname(bigfile_num, slice_num, mountpoint, "");
264 while (does_file_exist(tmp) || does_file_exist(tmp1)) {
265 // handle slices until end of CD
266 if (slice_num == 0) {
267 mr_msg(2, "ISO=%d bigfile=%ld --START--",
268 g_current_media_number, bigfile_num);
269 if (!(fin = fopen(tmp1,"r"))) {
270 mr_msg(2, "Cannot open bigfile's info file");
271 } else {
272 if (fread
273 ((void *) &biggiestruct, 1, sizeof(biggiestruct),
274 fin) < sizeof(biggiestruct)) {
275 mr_msg(2, "Unable to get biggiestruct");
276 }
277 paranoid_fclose(fin);
278 }
279 mr_asprintf(&tmp2, "%s/%s", bkpinfo->restore_path,
280 biggiestruct.filename);
281 mr_msg(2, "Opening biggiefile #%ld - '%s'", bigfile_num, tmp2);
282 if (!(forig = fopen(tmp2, "r"))) {
283 mr_msg(2, "Failed to open bigfile. Darn.");
284 retval++;
285 }
286 mr_free(tmp2);
287
288 slice_num++;
289 } else if (does_file_exist(tmp1)) {
290 mr_msg(2, "ISO=%d bigfile=%ld ---END---",
291 g_current_media_number, bigfile_num);
292 bigfile_num++;
293 paranoid_fclose(forig);
294 slice_num = 0;
295 } else {
296 mr_msg(2, "ISO=%d bigfile=%ld slice=%ld \r",
297 g_current_media_number, bigfile_num, slice_num);
298 if (bkpinfo->compression_level > 0) {
299 mr_asprintf(&command, "%s -dc %s 2>> %s", sz_exe, tmp, MONDO_LOGFILE);
300 } else {
301 mr_asprintf(&command, "cat %s", tmp);
302 }
303 if ((pin = popen(command, "r"))) {
304 res = 0;
305 while (!feof(pin)) {
306 currsizA = fread(bufblkA, 1, maxbufsize, pin);
307 if (currsizA <= 0) {
308 break;
309 }
310 currsizB = fread(bufblkB, 1, currsizA, forig);
311 if (currsizA != currsizB) {
312 res++;
313 } else {
314 for (j = 0;
315 j < currsizA && bufblkA[j] == bufblkB[j];
316 j++);
317 if (j < currsizA) {
318 res++;
319 }
320 }
321 }
322 paranoid_pclose(pin);
323 if (res && !strncmp(biggiestruct.filename, " /dev/", 5)) {
324 mr_msg(3,
325 "Ignoring differences between %s and live filesystem because it's a device and therefore the archives are stored via ntfsclone, not dd.",
326 biggiestruct.filename);
327 mr_msg(3,
328 "If you really want verification for %s, please contact the devteam and offer an incentive.",
329 biggiestruct.filename);
330 res = 0;
331 }
332 if (res) {
333 mr_msg(0,
334 "afio: \"%s\": Corrupt biggie file, says libmondo-archive.c",
335 biggiestruct.filename);
336 retval++;
337 }
338 }
339 mr_free(command);
340 slice_num++;
341 }
342 }
343 mr_free(tmp);
344 mr_free(tmp1);
345 mr_free(mountpoint);
346 mr_free(sz_exe);
347
348 last_bigfile_num = bigfile_num;
349 last_slice_num = slice_num - 1;
350 if (last_slice_num < 0) {
351 last_bigfile_num--;
352 }
353 close_evalcall_form();
354 if (bufblkA) {
355 mr_free(bufblkA);
356 }
357 if (bufblkB) {
358 mr_free(bufblkB);
359 }
360 return (0);
361}
362
363
364/**
365 * Verify one afioball from the CD.
366 * You should be changed to the root directory (/) for this to work.
367 * @param bkpinfo The backup information structure. Fields used:
368 * - @c bkpinfo->use_lzo
369 * - @c bkpinfo->tmpdir
370 * - @c bkpinfo->zip_exe
371 * - @c bkpinfo->zip_suffix
372 * @param tarball_fname The filename of the afioball to verify.
373 * @return 0, always.
374 */
375int verify_a_tarball(struct s_bkpinfo *bkpinfo, char *tarball_fname)
376{
377 /*@ buffers ********************************************************* */
378 char *command = NULL;
379 char *outlog = NULL;
380 char *tmp = NULL;
381
382 /*@ pointers ******************************************************* */
383 FILE *pin = NULL;
384
385 size_t n = 0;
386
387 /*@ long *********************************************************** */
388 long diffs = 0;
389
390 assert(bkpinfo != NULL);
391 assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
392
393 log_it("Verifying fileset '%s'", tarball_fname);
394
395 mr_asprintf(&outlog, "%s/afio.log", bkpinfo->tmpdir);
396
397 /* if programmer forgot to say which compression thingy to use then find out */
398 if (strstr(tarball_fname, ".lzo")
399 && strcmp(bkpinfo->zip_suffix, "lzo")) {
400 mr_msg(2, "OK, I'm going to start using lzop.");
401 mr_allocstr(bkpinfo->zip_exe, "lzop");
402 mr_allocstr(bkpinfo->zip_suffix, "lzo");
403 bkpinfo->use_lzo = TRUE;
404 bkpinfo->use_gzip = FALSE;
405 }
406 if (strstr(tarball_fname, ".gz")
407 && strcmp(bkpinfo->zip_suffix, "gz")) {
408 mr_msg(2, "OK, I'm going to start using gzip.");
409 strcpy(bkpinfo->zip_exe, "gzip");
410 strcpy(bkpinfo->zip_suffix, "gz");
411 bkpinfo->use_lzo = FALSE;
412 bkpinfo->use_gzip = TRUE;
413 }
414 if (strstr(tarball_fname, ".bz2")
415 && strcmp(bkpinfo->zip_suffix, "bz2")) {
416 mr_msg(2, "OK, I'm going to start using bzip2.");
417 mr_allocstr(bkpinfo->zip_exe, "bzip2");
418 mr_allocstr(bkpinfo->zip_suffix, "bz2");
419 bkpinfo->use_lzo = FALSE;
420 bkpinfo->use_gzip = FALSE;
421 }
422 unlink(outlog);
423 if (strstr(tarball_fname, ".star")) {
424 bkpinfo->use_star = TRUE;
425 if (strstr(tarball_fname, ".bz2")) {
426 mr_asprintf(&command,
427 "star -diff diffopts=mode,size,data file=%s %s >> %s 2>> %s",
428 tarball_fname,
429 (strstr(tarball_fname, ".bz2")) ? "-bz" : " ", outlog,
430 outlog);
431 } else {
432 mr_asprintf(&command,"");
433 }
434 } else {
435 bkpinfo->use_star = FALSE;
436 mr_asprintf(&command, "afio -r -P %s -Z %s >> %s 2>> %s",
437 bkpinfo->zip_exe, tarball_fname, outlog, outlog);
438 }
439 mr_msg(6, "command=%s", command);
440 paranoid_system(command);
441 mr_free(command);
442
443 if (length_of_file(outlog) < 10) {
444 /* BERLIOS: This seems useless !! */
445 mr_asprintf(&command, "cat %s >> %s", outlog, MONDO_LOGFILE);
446 } else {
447 mr_asprintf(&command, "cut -d':' -f%d %s | sort -u",
448 (bkpinfo->use_star) ? 1 : 2, outlog);
449 pin = popen(command, "r");
450 if (pin) {
451 for (mr_getline(&tmp, &n, pin); !feof(pin);
452 mr_getline(&tmp, &n, pin)) {
453 if (bkpinfo->use_star) {
454 if (!strstr(tmp, "diffopts=")) {
455 while (strlen(tmp) > 0
456 && tmp[strlen(tmp) - 1] < 32) {
457 tmp[strlen(tmp) - 1] = '\0';
458 }
459 if (strchr(tmp, '/')) {
460 if (!diffs) {
461 mr_msg(0, "'%s' - differences found",
462 tarball_fname);
463 }
464 mr_msg(0, "star: /%s",
465 strip_afio_output_line(tmp));
466 diffs++;
467 }
468 }
469 } else {
470 if (!diffs) {
471 mr_msg(0, "'%s' - differences found",
472 tarball_fname);
473 }
474 mr_msg(0, "afio: /%s", strip_afio_output_line(tmp));
475 diffs++;
476 }
477 }
478 paranoid_pclose(pin);
479 mr_free(tmp);
480 } else {
481 log_OS_error(command);
482 }
483 }
484 mr_free(outlog);
485 mr_free(command);
486
487 return (0);
488}
489
490
491/**
492 * Verify one afioball from the CD.
493 * Checks for existence (calls fatal_error() if it does not exist) and
494 * then calls verify_an_afioball().
495 * @param bkpinfo The backup information structure. Passed to verify_an_afioball().
496 * @param tarball_fname The filename of the afioball to verify.
497 * @return The return value of verify_an_afioball().
498 * @see verify_an_afioball
499 */
500int
501verify_an_afioball_from_CD(struct s_bkpinfo *bkpinfo, char *tarball_fname)
502{
503
504 /*@ int ************************************************************* */
505 int res = 0;
506
507 assert(bkpinfo != NULL);
508 assert_string_is_neither_NULL_nor_zerolength(tarball_fname);
509
510 mr_msg(1, "Verifying %s", tarball_fname);
511 if (!does_file_exist(tarball_fname)) {
512 fatal_error("Cannot verify nonexistent afioball");
513 }
514 res = verify_a_tarball(bkpinfo, tarball_fname);
515 return (res);
516}
517
518
519/**
520 * Verify one afioball from the opened tape/CD stream.
521 * Copies the file from tape to tmpdir and then calls verify_an_afioball().
522 * @param bkpinfo The backup information structure. Passed to verify_an_afioball().
523 * @param orig_fname The original filename of the afioball to verify.
524 * @param size The size of the afioball to verify.
525 * @return The return value of verify_an_afioball().
526 * @see verify_an_afioball
527 */
528int
529verify_an_afioball_from_stream(struct s_bkpinfo *bkpinfo, char *orig_fname,
530 long long size)
531{
532
533 /*@ int ************************************************************** */
534 int retval = 0;
535 int res = 0;
536
537 /*@ buffers ********************************************************** */
538 char *tmp = NULL;
539 char *tarball_fname = NULL;
540
541 /*@ pointers ********************************************************* */
542 char *p = NULL;
543
544 assert(bkpinfo != NULL);
545 assert_string_is_neither_NULL_nor_zerolength(orig_fname);
546
547 p = strrchr(orig_fname, '/');
548 if (!p) {
549 p = orig_fname;
550 } else {
551 p++;
552 }
553 mr_asprintf(&tmp, "mkdir -p %s/tmpfs", bkpinfo->tmpdir);
554 paranoid_system(tmp);
555 mr_free(tmp);
556
557 mr_asprintf(&tarball_fname, "%s/tmpfs/temporary-%s", bkpinfo->tmpdir, p);
558 read_file_from_stream_to_file(bkpinfo, tarball_fname, size);
559 res = verify_a_tarball(bkpinfo, tarball_fname);
560 if (res) {
561 mr_msg(0, "Afioball '%s' no longer matches your live filesystem", p);
562 retval++;
563 }
564 unlink(tarball_fname);
565 mr_free(tarball_fname);
566 return (retval);
567}
568
569
570/**
571 * Verify one biggiefile form the opened tape/CD stream.
572 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir is the only field used.
573 * @param biggie_fname The filename of the biggiefile to verify.
574 * @param size The size in bytes of said biggiefile.
575 * @return 0 for success (even if the file doesn't match); nonzero for a tape error.
576 */
577int
578verify_a_biggiefile_from_stream(struct s_bkpinfo *bkpinfo,
579 char *biggie_fname, long long size)
580{
581
582 /*@ int ************************************************************* */
583 int retval = 0;
584 int res = 0;
585 int current_slice_number = 0;
586 int ctrl_chr = '\0';
587
588 /*@ char ************************************************************ */
589 char *test_file = NULL;
590 char *biggie_cksum = NULL;
591 char *orig_cksum = NULL;
592 char *tmp = NULL;
593 char *slice_fnam = (char *) &res;
594
595 /*@ pointers ******************************************************** */
596 char *p;
597
598 /*@ long long ******************************************************* */
599 long long slice_siz;
600
601 assert(bkpinfo != NULL);
602 assert_string_is_neither_NULL_nor_zerolength(biggie_fname);
603
604 p = strrchr(biggie_fname, '/');
605 if (!p) {
606 p = biggie_fname;
607 } else {
608 p++;
609 }
610 mr_asprintf(&test_file, "%s/temporary-%s", bkpinfo->tmpdir, p);
611 for (res =
612 read_header_block_from_stream(&slice_siz, slice_fnam, &ctrl_chr);
613 ctrl_chr != BLK_STOP_A_BIGGIE;
614 res =
615 read_header_block_from_stream(&slice_siz, slice_fnam,
616 &ctrl_chr)) {
617 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
618 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
619 }
620 res = read_file_from_stream_to_file(bkpinfo, test_file, slice_siz);
621 unlink(test_file);
622 mr_free(slice_fnam);
623 slice_fnam = (char *) &res;
624 res =
625 read_header_block_from_stream(&slice_siz, slice_fnam,
626 &ctrl_chr);
627 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
628 mr_msg(2, "test_file = %s", test_file);
629 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
630 }
631 current_slice_number++;
632 retval += res;
633 mr_free(slice_fnam);
634 slice_fnam = (char *) &res;
635 }
636 mr_free(test_file);
637
638 mr_asprintf(&biggie_cksum, slice_fnam);
639 mr_free(slice_fnam);
640
641 if (biggie_cksum[0] != '\0') {
642 orig_cksum = calc_checksum_of_file(biggie_fname);
643 if (strcmp(biggie_cksum, orig_cksum)) {
644 mr_asprintf(&tmp, "orig cksum=%s; curr cksum=%s", biggie_cksum,
645 orig_cksum);
646 mr_msg(2, tmp);
647 mr_free(tmp);
648
649 mr_asprintf(&tmp, _("%s has changed on live filesystem"),
650 biggie_fname);
651 log_to_screen(tmp);
652 mr_free(tmp);
653
654 mr_asprintf(&tmp, "echo \"%s\" >> /tmp/biggies.changed",
655 biggie_fname);
656 system(tmp);
657 mr_free(tmp);
658 }
659 mr_free(orig_cksum);
660 }
661 mr_free(biggie_cksum);
662 return (retval);
663}
664
665
666/**
667 * Verify all afioballs from the opened tape/CD stream.
668 * @param bkpinfo The backup information structure. Fields used:
669 * - @c bkpinfo->restore_path
670 * - @c bkpinfo->tmpdir
671 *
672 * @return 0 for success (even if there are differences); nonzero for a tape error.
673 */
674int verify_afioballs_from_stream(struct s_bkpinfo *bkpinfo)
675{
676 /*@ int ********************************************************** */
677 int retval = 0;
678 int res = 0;
679 long current_afioball_number = 0;
680 int ctrl_chr = 0;
681 int total_afioballs = 0;
682
683 /*@ buffers ***************************************************** */
684 char *tmp = NULL;
685 char *fname = (char *) &res; /* Should NOT be NULL */
686 char *curr_xattr_list_fname = NULL;
687 char *curr_acl_list_fname = NULL;
688
689 /*@ long long *************************************************** */
690 long long size = 0;
691
692 assert(bkpinfo != NULL);
693
694 if (g_getfattr) {
695 mr_asprintf(&curr_xattr_list_fname, XATTR_BIGGLST_FNAME_RAW_SZ,
696 bkpinfo->tmpdir);
697 }
698 if (g_getfacl) {
699 mr_asprintf(&curr_acl_list_fname, ACL_BIGGLST_FNAME_RAW_SZ,
700 bkpinfo->tmpdir);
701 }
702 log_to_screen(_("Verifying regular archives on tape"));
703 total_afioballs = get_last_filelist_number(bkpinfo) + 1;
704 open_progress_form(_("Verifying filesystem"),
705 _("I am verifying archives against your live filesystem now."),
706 _("Please wait. This may take a couple of hours."), "",
707 total_afioballs);
708 res = read_header_block_from_stream(&size, NULL, &ctrl_chr);
709 if (ctrl_chr != BLK_START_AFIOBALLS) {
710 iamhere("YOU SHOULD NOT GET HERE");
711 iamhere("Grabbing the EXAT files");
712 if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
713 res =
714 read_EXAT_files_from_tape(bkpinfo, &size, NULL, &ctrl_chr,
715 curr_xattr_list_fname,
716 curr_acl_list_fname);
717 }
718 }
719 if (ctrl_chr != BLK_START_AFIOBALLS) {
720 wrong_marker(BLK_START_AFIOBALLS, ctrl_chr);
721 }
722 mr_free(curr_xattr_list_fname);
723 mr_free(curr_acl_list_fname);
724
725 for (res = read_header_block_from_stream(&size, fname, &ctrl_chr);
726 ctrl_chr != BLK_STOP_AFIOBALLS;
727 res = read_header_block_from_stream(&size, fname, &ctrl_chr)) {
728 if (g_getfattr) {
729 mr_asprintf(&curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
730 bkpinfo->tmpdir, current_afioball_number);
731 }
732 if (g_getfacl) {
733 mr_asprintf(&curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
734 bkpinfo->tmpdir, current_afioball_number);
735 }
736 if (ctrl_chr == BLK_START_EXTENDED_ATTRIBUTES) {
737 iamhere("Reading EXAT files from tape");
738 mr_free(fname);
739 fname = (char *) &res;
740 res =
741 read_EXAT_files_from_tape(bkpinfo, &size, fname, &ctrl_chr,
742 curr_xattr_list_fname,
743 curr_acl_list_fname);
744 }
745 mr_free(curr_xattr_list_fname);
746 mr_free(curr_acl_list_fname);
747
748 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
749 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
750 }
751 mr_asprintf(&tmp, "Verifying fileset #%ld", current_afioball_number);
752 update_progress_form(tmp);
753 mr_free(tmp);
754
755 res = verify_an_afioball_from_stream(bkpinfo, fname, size);
756 if (res) {
757 mr_asprintf(&tmp, _("Afioball %ld differs from live filesystem"),
758 current_afioball_number);
759 log_to_screen(tmp);
760 mr_free(tmp);
761 }
762 retval += res;
763 current_afioball_number++;
764 g_current_progress++;
765 mr_free(fname);
766 fname = (char *) &res;
767 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
768 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
769 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
770 }
771 mr_free(fname);
772 fname = (char *) &res;
773 }
774 mr_msg(1, "All done with afioballs");
775 close_progress_form();
776 mr_free(fname);
777 return (retval);
778}
779
780
781/**
782 * Verify all biggiefiles on the opened CD/tape stream.
783 * @param bkpinfo The backup information structure. Fields used:
784 * - @c bkpinfo->restore_path
785 * - @c bkpinfo->tmpdir
786 *
787 * @return 0 for success (even if there are differences); nonzero for a tape error.
788 */
789int verify_biggiefiles_from_stream(struct s_bkpinfo *bkpinfo)
790{
791
792 /*@ int ************************************************************ */
793 int retval = 0;
794 int res = 0;
795 int ctrl_chr = 0;
796
797 /*@ long *********************************************************** */
798 long noof_biggiefiles = 0;
799 long current_biggiefile_number = 0;
800
801 /*@ buffers ******************************************************** */
802 char *orig_fname = (char *) &ctrl_chr; /* Should NOT be NULL */
803 char *logical_fname = NULL;
804 char *comment = NULL;
805 char *curr_xattr_list_fname = NULL;
806 char *curr_acl_list_fname = NULL;
807 /*@ pointers ******************************************************* */
808 char *p = NULL;
809
810 /*@ long long size ************************************************* */
811 long long size = 0;
812
813 assert(bkpinfo != NULL);
814
815 if (g_getfattr) {
816 mr_asprintf(&curr_xattr_list_fname, XATTR_BIGGLST_FNAME_RAW_SZ,
817 bkpinfo->tmpdir);
818 }
819 if (g_getfacl) {
820 mr_asprintf(&curr_acl_list_fname, ACL_BIGGLST_FNAME_RAW_SZ,
821 bkpinfo->tmpdir);
822 }
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 mr_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 = NULL;
911 char *command = NULL;
912 char *tmp = NULL;
913 char *fname = NULL;
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 mr_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 mr_free(command);
971 return (1);
972 }
973 mr_free(command);
974 }
975 mr_msg(2, "OK, I've mounted the ISO/CD\n");
976 mr_asprintf(&tmp, "%s/archives/NOT-THE-LAST", mountpoint);
977 if (!does_file_exist(tmp)) {
978 mr_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 mr_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 mr_asprintf(&command, "umount %s", mountpoint);
995#ifdef __FreeBSD__
996 ret = 0;
997 ret += system(command);
998 ret += kick_vn(mddevice);
999 if (ret)
1000#else
1001 if (system(command))
1002#endif
1003 {
1004 mr_asprintf(&tmp, "%s failed; unable to unmount ISO image\n",
1005 command);
1006 log_to_screen(tmp);
1007 mr_free(tmp);
1008 retval++;
1009 } else {
1010 mr_msg(2, "OK, I've unmounted the ISO file\n");
1011 }
1012 mr_free(command);
1013 mr_free(mountpoint);
1014
1015 if (!does_file_exist(fname)) {
1016 mr_asprintf(&command, "umount %s", bkpinfo->media_device);
1017 run_program_and_log_output(command, 2);
1018 mr_free(command);
1019
1020 if (!bkpinfo->please_dont_eject
1021 && eject_device(bkpinfo->media_device)) {
1022 mr_msg(2, "Failed to eject CD-ROM drive");
1023 }
1024 }
1025 mr_free(fname);
1026 return (retval);
1027}
1028
1029
1030/**
1031 * Verify all backups on tape.
1032 * This should be done after the backup process has already closed the tape.
1033 * @param bkpinfo The backup information structure. Passed to various helper functions.
1034 * @return 0 for success (even if thee were differences), nonzero for failure.
1035 * @ingroup verifyGroup
1036 */
1037int verify_tape_backups(struct s_bkpinfo *bkpinfo)
1038{
1039
1040 /*@ int ************************************************************ */
1041 int retval = 0;
1042
1043 /*@ buffers ******************************************************** */
1044 char *tmp = NULL;
1045 char *changed_files_fname = NULL;
1046
1047 /*@ long *********************************************************** */
1048 long diffs = 0;
1049
1050 assert(bkpinfo != NULL);
1051
1052 mr_msg(3, "verify_tape_backups --- starting");
1053 log_to_screen(_("Verifying backups"));
1054 openin_tape(bkpinfo);
1055
1056 /* verify archives themselves */
1057 retval += verify_afioballs_from_stream(bkpinfo);
1058 retval += verify_biggiefiles_from_stream(bkpinfo);
1059
1060 /* find the final blocks */
1061 sync();
1062 sleep(2);
1063 closein_tape(bkpinfo);
1064
1065 /* close tape; exit */
1066 paranoid_system
1067 ("rm -f /tmp/biggies.changed /tmp/changed.files.[0-9]* 2> /dev/null");
1068 mr_asprintf(&changed_files_fname, "/tmp/changed.files.%d",
1069 (int) (random() % 32767));
1070 mr_asprintf(&tmp,
1071 "grep -E '^%s:.*$' %s | cut -d'\"' -f2 | sort -u | awk '{print \"/\"$0;};' | tr -s '/' '/' | grep -v \"(total of\" | grep -v \"incheckentry.*xwait\" | grep -vE '^/afio:.*$' | grep -vE '^dev/.*$' > %s",
1072 (bkpinfo->use_star) ? "star" : "afio", MONDO_LOGFILE,
1073 changed_files_fname);
1074 mr_msg(2, "Running command to derive list of changed files");
1075 mr_msg(2, tmp);
1076 if (system(tmp)) {
1077 if (does_file_exist(changed_files_fname)
1078 && length_of_file(changed_files_fname) > 2) {
1079 log_to_screen
1080 (_("Warning - unable to check logfile to derive list of changed files"));
1081 } else {
1082 log_to_screen
1083 (_("No differences found. Therefore, no 'changed.files' text file."));
1084 }
1085 }
1086 mr_free(tmp);
1087
1088 mr_asprintf(&tmp, "cat /tmp/biggies.changed >> %s", changed_files_fname);
1089 paranoid_system(tmp);
1090 mr_free(tmp);
1091
1092 diffs = count_lines_in_file(changed_files_fname);
1093 if (diffs > 0) {
1094 mr_asprintf(&tmp, "cp -f %s %s", changed_files_fname,
1095 "/tmp/changed.files");
1096 run_program_and_log_output(tmp, FALSE);
1097 mr_free(tmp);
1098
1099 mr_asprintf(&tmp,
1100 "%ld files differed from live filesystem; type less %s or less %s to see",
1101 diffs, changed_files_fname, "/tmp/changed.files");
1102 mr_msg(0, tmp);
1103 mr_free(tmp);
1104
1105 log_to_screen
1106 (_("See /tmp/changed.files for a list of nonmatching files."));
1107 log_to_screen
1108 (_("The files probably changed on filesystem, not on backup media."));
1109 // retval++;
1110 }
1111 mr_free(changed_files_fname);
1112 return (retval);
1113}
1114
1115
1116/**
1117 * Generate the filename of a tarball to verify.
1118 * @param bkpinfo The backup information structure. @c bkpinfo->zip_suffix is the only field used.
1119 * @param mountpoint The directory where the CD/DVD/ISO is mounted.
1120 * @param setno The afioball number to get the location of.
1121 * @return The absolute path to the afioball.
1122 * @note The returned string points to static data that will be overwritten with each call.
1123 * @ingroup stringGroup
1124 */
1125char *vfy_tball_fname(struct s_bkpinfo *bkpinfo, char *mountpoint,
1126 int setno)
1127{
1128 /*@ buffers ******************************************************* */
1129 static char *output;
1130
1131 assert(bkpinfo != NULL);
1132 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1133 mr_asprintf(&output, "%s/archives/%d.star.%s", mountpoint, setno,
1134 bkpinfo->zip_suffix);
1135 if (!does_file_exist(output)) {
1136 mr_free(output);
1137 mr_asprintf(&output, "%s/archives/%d.afio.%s", mountpoint, setno,
1138 bkpinfo->zip_suffix);
1139 }
1140 return (output);
1141}
Note: See TracBrowser for help on using the repository browser.