source: MondoRescue/branches/3.1/mondo/src/common/libmondo-verify.c@ 3190

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