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

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

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

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