source: MondoRescue/branches/3.1/mondo/src/common/libmondo-stream.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: 49.8 KB
Line 
1/* libmondo-stream.c
2 $Id: libmondo-stream.c 3190 2013-09-25 06:55:43Z bruno $
3
4...tools for talking to tapes, Monitas streams, etc.
5
6*/
7
8
9/**
10 * @file
11 * Functions for writing data to/reading data from streams (tape, CD stream, etc.)
12 */
13
14#include "my-stuff.h"
15#include "mr_mem.h"
16#include "mondostructures.h"
17#include "libmondo-devices.h"
18#include "lib-common-externs.h"
19#include "libmondo-stream.h"
20#include "libmondo-string-EXT.h"
21#include "libmondo-files-EXT.h"
22#include "libmondo-gui-EXT.h"
23#include "libmondo-fork-EXT.h"
24#include "libmondo-tools-EXT.h"
25#include "libmondo-fifo-EXT.h"
26
27#define EXTRA_TAPE_CHECKSUMS
28#define STR_HEADER "Mondolicious, baby"
29
30/*@unused@*/
31//static char cvsid[] = "$Id: libmondo-stream.c 3190 2013-09-25 06:55:43Z bruno $";
32extern bool g_sigpipe;
33extern int g_tape_buffer_size_MB;
34
35extern char *g_getfacl;
36extern char *g_getfattr;
37extern char *MONDO_LOGFILE;
38
39/* Reference to global bkpinfo */
40extern struct s_bkpinfo *bkpinfo;
41
42/**
43 * @addtogroup globalGroup
44 * @{
45 */
46/**
47 * The file pointer for the opened tape/CD stream.
48 * Opened and closed by openin_tape(), openin_cdstream(),
49 * openout_tape(), openout_cdstream(), closein_tape(), closein_cdstream(),
50 * closeout_tape(), and closeout_cdstream().
51 */
52FILE *g_tape_stream = NULL;
53
54
55/**
56 * The position (in kilobytes) where we are on the tape.
57 */
58long long g_tape_posK = 0;
59
60/**
61 * The current media number we're using. This value is 1-based.
62 */
63int g_current_media_number = -1;
64
65/**
66 * The tape catalog that keeps track of files written to tape.
67 */
68struct s_tapecatalog *g_tapecatalog;
69
70/* @} - end of globalGroup */
71
72int write_backcatalog_to_tape();
73
74
75
76
77
78/**
79 * @addtogroup streamGroup
80 * @{
81 */
82/**
83 * Close the global output file descriptor which Mondo has used to read
84 * from the CD stream.
85 * @param bkpinfo The backup information structure. Passed directly to closein_tape().
86 * @return 0 for success, nonzero for failure.
87 * @note This should be called by restore processes only.
88 */
89int closein_cdstream()
90{
91 return (closein_tape());
92}
93
94
95/**
96 * Close the global output file descriptor which Mondo has used to read
97 * from buffer or dd, which read from the tape.
98 * @param bkpinfo The backup information structure. Unused.
99 * @return 0 for success, nonzero for failure.
100 * @note This should be called by restore processes only.
101 * @note This function also works for cdstreams for now, but don't count on this behavior.
102 * @bug @p bkpinfo parameter is unused.
103 */
104int closein_tape()
105{
106 /*@ int's ******************************************************* */
107 int retval = 0;
108 int res = 0;
109 int ctrl_chr = '\0';
110
111 /*@ buffers ***************************************************** */
112 char fname[MAX_STR_LEN];
113
114 /*@ long long's ************************************************* */
115 long long size;
116 char *blk;
117 int i;
118 int j;
119
120 blk = (char *) malloc(256 * 1024);
121
122 log_it("closein_tape() -- entering");
123 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
124 retval += res;
125 if (ctrl_chr != BLK_END_OF_BACKUP) {
126 wrong_marker(BLK_END_OF_BACKUP, ctrl_chr);
127 }
128 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
129 retval += res;
130 if (ctrl_chr != BLK_END_OF_TAPE) {
131 wrong_marker(BLK_END_OF_TAPE, ctrl_chr);
132 }
133 for (i = 0; i < 8 && !feof(g_tape_stream); i++) {
134 j = fread(blk, 1, 256 * 1024, g_tape_stream);
135 if (j) {
136 // FIXME
137 }
138 }
139 sleep(1);
140 sync();
141 sleep(1);
142 paranoid_pclose(g_tape_stream);
143 log_it("closein_tape() -- leaving");
144 if (!bkpinfo->please_dont_eject) {
145 eject_device(bkpinfo->media_device);
146 }
147 paranoid_free(blk);
148 paranoid_free(g_tapecatalog);
149 return (retval);
150}
151
152
153
154/**
155 * Close the global output file descriptor which Mondo has been using to write
156 * to the tape device (via buffer or dd).
157 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
158 * @return 0 for success, nonzero for failure.
159 * @note This should be called by backup processes only.
160 */
161int closeout_tape()
162{
163 /*@ int's ******************************************************* */
164 int retval = 0;
165// int res = 0;
166// int ctrl_chr = '\0';
167
168 /*@ buffers ***************************************************** */
169// char fname[MAX_STR_LEN];
170
171 /*@ long long's ************************************************* */
172// long long size;
173 int i;
174 char *blk;
175
176 blk = (char *) malloc(256 * 1024);
177
178 sleep(1);
179 sync();
180 sleep(1);
181 log_it("closeout_tape() -- entering");
182 retval +=
183 write_header_block_to_stream((off_t)0, "end-of-backup",
184 BLK_END_OF_BACKUP);
185 retval += write_header_block_to_stream((off_t)0, "end-of-tape", BLK_END_OF_TAPE); /* just in case */
186/* write 1MB of crap */
187 for (i = 0; i < 256 * 1024; i++) {
188 blk[i] = (int) (random() & 0xFF);
189 }
190 for (i = 0; i < 4 * 8; i++) {
191 if (fwrite(blk, 1, 256 * 1024, g_tape_stream)) {
192 //FIXME
193 }
194 if (should_we_write_to_next_tape
195 (bkpinfo->media_size, (off_t)256 * 1024)) {
196 start_to_write_to_next_tape();
197 }
198 }
199/* write 1MB of zeroes */
200/*
201 for (i = 0; i < 256*1024; i++)
202 {
203 blk[i] = 0;
204 }
205 for (i = 0; i < 4; i++)
206 {
207 fwrite (blk, 1, 256*1024, g_tape_stream);
208 if (should_we_write_to_next_tape (bkpinfo->media_size, 256*1024))
209 {
210 start_to_write_to_next_tape ();
211 }
212 }
213*/
214 sleep(2);
215 paranoid_pclose(g_tape_stream);
216 log_it("closeout_tape() -- leaving");
217 for (i = 0; i < g_tapecatalog->entries; i++) {
218 log_it("i=%d type=%s num=%d aux=%ld posK=%lld", i,
219 (g_tapecatalog->el[i].type ==
220 fileset) ? "fileset" : "bigslice",
221 g_tapecatalog->el[i].number, g_tapecatalog->el[i].aux,
222 g_tapecatalog->el[i].tape_posK);
223 }
224 paranoid_free(blk);
225 paranoid_free(g_tapecatalog);
226 return (retval);
227}
228
229
230
231bool mt_says_tape_exists(char *dev)
232{
233 char *command = NULL;
234 int res;
235
236 mr_asprintf(command, "mt -f %s status", dev);
237 res = run_program_and_log_output(command, 1);
238 mr_free(command);
239
240 if (res) {
241 return (FALSE);
242 } else {
243 return (TRUE);
244 }
245}
246
247
248
249/**
250 * Determine the name of the tape device. Tries the SCSI tape for
251 * this platform, then the IDE tape, then "/dev/st0", then "/dev/osst0".
252 * @return the allocated tape string if success, NULL if failure
253 */
254char *mr_find_tape_device(void) {
255
256 char *tmp = NULL;
257 char *command = NULL;
258 char *cdr_exe = NULL;
259 char *dev = NULL;
260 int res;
261
262 log_to_screen("I am looking for your tape streamer. Please wait.");
263
264 tmp = find_home_of_exe("cdrecord");
265 if (tmp) {
266 mr_asprintf(cdr_exe, "cdrecord");
267 } else {
268 mr_asprintf(cdr_exe, "dvdrecord");
269 }
270 mr_free(tmp);
271
272 mr_asprintf(command, "%s -scanbus 2> /dev/null | grep -i tape | wc -l", cdr_exe);
273 tmp = call_program_and_get_last_line_of_output(command,TRUE);
274 mr_free(command);
275
276 if (atoi(tmp) != 1) {
277 log_it("Either too few or too many tape streamers for me to detect...");
278 mr_asprintf(dev, "%s", VANILLA_SCSI_TAPE);
279 mr_free(tmp);
280 mr_free(cdr_exe);
281 return(dev);
282 }
283 mr_free(tmp);
284
285 mr_asprintf(command, "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | cut -d' ' -f2 | head -n1", cdr_exe);
286 tmp = call_program_and_get_last_line_of_output(command,TRUE);
287 mr_free(command);
288
289 if (strlen(tmp) < 2) {
290 log_it("Could not find tape device");
291 mr_free(cdr_exe);
292 mr_free(tmp);
293 return(NULL);
294 }
295 mr_free(tmp);
296
297 mr_asprintf(command, "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | cut -d' ' -f3 | cut -d')' -f1 | head -n1", cdr_exe);
298 mr_free(cdr_exe);
299
300 tmp = call_program_and_get_last_line_of_output(command,TRUE);
301 mr_free(command);
302
303 mr_asprintf(dev, "%s", "/dev/st");
304 mr_strcat(dev, tmp); // e.g. '/dev/st0' becomes '/dev/stN'
305 mr_free(tmp);
306
307 res = 0;
308 if (!mt_says_tape_exists(dev)) {
309 mr_free(dev);
310 mr_asprintf(dev, "%s", ALT_TAPE);
311 if (!mt_says_tape_exists(dev)) {
312 log_it("Cannot openin %s", dev);
313 mr_free(dev);
314 mr_asprintf(dev, "/dev/st0");
315 if (!mt_says_tape_exists(dev)) {
316 log_it("Cannot openin %s", dev);
317 mr_free(dev);
318 mr_asprintf(dev, "/dev/osst0");
319 if (!mt_says_tape_exists(dev)) {
320 mr_free(dev);
321 res++;
322 } else {
323 res = 0;
324 }
325 }
326 }
327 }
328
329 if (dev) {
330 log_it("At this point, dev = %s and res = %d", dev, res);
331 } else {
332 log_it("At this point, dev is NULL and res = %d", dev, res);
333 }
334
335 tmp = call_program_and_get_last_line_of_output(" cdrecord -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | awk '{for(i=1; i<NF; i++) { if (index($i, \"GB\")>0) { print $i;};};};'",TRUE);
336
337 if (mt_says_tape_exists(dev)) {
338 res = 0;
339 } else {
340 log_it("Turning %s", dev);
341 mr_free(tmp);
342 mr_asprintf(tmp, "%s", (strrchr(dev, '/') != NULL) ? strrchr(dev, '/') : dev);
343 mr_free(dev);
344 mr_asprintf(dev, "/dev/os%s", tmp);
345 log_it("...into %s", dev);
346 if (mt_says_tape_exists(dev)) {
347 res = 0;
348 } else {
349 mr_free(dev);
350 res++;
351 }
352 }
353
354 if (dev) {
355 log_it("At this new point, dev = %s and res = %d", dev, res);
356 } else {
357 log_it("At this new point, dev is NULL and res = %d", res);
358 }
359
360 if (strlen(tmp) < 2) {
361 log_it("Warning - size of tape unknown");
362 }
363 mr_free(tmp);
364 return(dev);
365}
366
367
368int read_EXAT_files_from_tape(long long *ptmp_size, char *tmp_fname,
369 int *pctrl_chr, char *xattr_fname,
370 char *acl_fname)
371{
372 int res = 0;
373 char fname_buf[PATH_MAX];
374 char *fname = (char *)fname_buf; /* Should NOT be NULL */
375 char *tmp = NULL;
376
377 // xattr
378 if (g_getfattr) {
379 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
380 if (*pctrl_chr != BLK_START_EXAT_FILE) {
381 wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
382 }
383 if (strstr(fname, "xattr") == NULL) {
384 mr_asprintf(tmp,"Wrong order expected xattr, got %s, sunshine.", fname);
385 fatal_error(tmp);
386 }
387 read_file_from_stream_to_file(xattr_fname, *ptmp_size);
388 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
389 if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
390 wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
391 }
392 log_msg(1, "Got xattr");
393 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
394 if (*pctrl_chr != BLK_STOP_EXTENDED_ATTRIBUTES) {
395 wrong_marker(BLK_STOP_EXTENDED_ATTRIBUTES, *pctrl_chr);
396 }
397 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
398 if (*pctrl_chr == BLK_START_AN_AFIO_OR_SLICE) {
399 log_msg(1, "No acl attributes found, skipping to afio files");
400 return(0);
401 } else {
402 if (*pctrl_chr != BLK_START_EXTENDED_ATTRIBUTES) {
403 wrong_marker(BLK_START_EXTENDED_ATTRIBUTES, *pctrl_chr);
404 }
405 }
406 }
407 // acl
408 if (g_getfacl) {
409 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
410 if (*pctrl_chr != BLK_START_EXAT_FILE) {
411 wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
412 }
413 if (strstr(fname, "acl") == NULL) {
414 mr_asprintf(tmp,"Wrong order expected acl, got %s, sunshine.", fname);
415 fatal_error(tmp);
416 }
417 read_file_from_stream_to_file(acl_fname, *ptmp_size);
418 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
419 if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
420 wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
421 }
422 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
423 if (*pctrl_chr != BLK_STOP_EXTENDED_ATTRIBUTES) {
424 wrong_marker(BLK_STOP_EXTENDED_ATTRIBUTES, *pctrl_chr);
425 }
426 log_msg(1, "Got acl");
427 }
428 // tarball itself
429 res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
430 log_msg(1, "End of extended attributes, now looking for afioball");
431 return (res);
432}
433
434
435int write_EXAT_files_to_tape(char *xattr_fname,
436 char *acl_fname)
437{
438 int res = 0;
439 if (g_getfattr) {
440 // xattr
441 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
442 BLK_START_EXTENDED_ATTRIBUTES);
443 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
444 BLK_START_EXAT_FILE);
445 write_file_to_stream_from_file(xattr_fname);
446 write_header_block_to_stream((off_t)-1, xattr_fname, BLK_STOP_EXAT_FILE);
447 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
448 BLK_STOP_EXTENDED_ATTRIBUTES);
449 }
450 if (g_getfacl) {
451 // acl
452 write_header_block_to_stream(length_of_file(acl_fname), acl_fname,
453 BLK_START_EXTENDED_ATTRIBUTES);
454 write_header_block_to_stream(length_of_file(acl_fname), acl_fname,
455 BLK_START_EXAT_FILE);
456 write_file_to_stream_from_file(acl_fname);
457 write_header_block_to_stream((off_t)-1, acl_fname, BLK_STOP_EXAT_FILE);
458 write_header_block_to_stream(length_of_file(acl_fname), acl_fname,
459 BLK_STOP_EXTENDED_ATTRIBUTES);
460 }
461 return (res);
462}
463
464
465
466
467/**
468 * Tell the user to insert tape @p tapeno and wait for it to settle (5 seconds).
469 * @param tapeno The tape number to insist on.
470 * @bug There is currently no way to actually verify that the user has actually
471 * inserted the right tape.
472 */
473void insist_on_this_tape_number(int tapeno)
474{
475 int i;
476 char *tmp = NULL;
477
478 log_it("Insisting on tape #%d", tapeno);
479 if (g_current_media_number != tapeno) {
480 mr_asprintf(tmp, "When the tape drive goes quiet, please insert volume %d in this series.", tapeno);
481 popup_and_OK(tmp);
482 mr_free(tmp);
483 open_evalcall_form("Waiting while the tape drive settles");
484 } else {
485 open_evalcall_form("Waiting while the tape drive rewinds");
486 }
487
488 for (i = 0; i <= 100; i += 2) {
489 usleep(100000);
490 update_evalcall_form(i);
491 }
492 close_evalcall_form();
493 log_it("I assume user has inserted it. They _say_ they have...");
494 g_current_media_number = tapeno;
495
496 // log_it("g_current_media_number = %d", g_current_media_number);
497 log_it("OK, I've finished insisting. On with the revelry.");
498}
499
500
501
502
503/**
504 * Debugging aid - log the offset we're at on the tape (reading or writing).
505 */
506void log_tape_pos(void)
507{
508 /*@ buffers ***************************************************** */
509
510
511 /*@ end vars *************************************************** */
512
513 log_it("Tape position -- %ld KB (%ld MB)", (long) g_tape_posK,
514 (long) g_tape_posK >> 10);
515}
516
517
518
519
520/**
521 * Add a file to a collection of recently archived filesets/slices.
522 * The type is determined by the filename: if it contains ".afio." it is
523 * assumed to be a fileset, otherwise if it contains "slice" it's a slice,
524 * otherwise we generate a fatal_error().
525 * @param latest_fname The file to place in the collection.
526 * @return 0, always.
527 * @bug Return value is redundant.
528 * @bug The detection won't work for uncompressed afioballs (they end in ".afio", no dot afterwards). // Not true. They end in '.' -Hugo
529 */
530int maintain_collection_of_recent_archives(char *latest_fname)
531{
532 long long final_alleged_writeK, final_projected_certain_writeK,
533 cposK, bufsize_K;
534 int last, curr, i;
535 char *command = NULL;
536 char *tmpdir = NULL;
537 char *old_fname = NULL;
538
539 bufsize_K = (long long) (1024LL * (1 + g_tape_buffer_size_MB));
540 mr_asprintf(tmpdir, "%s/tmpfs/backcatalog", bkpinfo->tmpdir);
541 mkdir(tmpdir, 0x700);
542 mr_asprintf(command, "cp -f %s %s", latest_fname, tmpdir);
543 if (run_program_and_log_output(command, 6)) {
544 log_it("Warning - failed to copy %s to backcatalog at %s",
545 latest_fname, tmpdir);
546 }
547 mr_free(command);
548
549 last = g_tapecatalog->entries - 1;
550 if (last <= 0) {
551 log_it("Too early to start deleting from collection.");
552 mr_free(tmpdir);
553 return (0);
554 }
555 final_alleged_writeK = g_tapecatalog->el[last].tape_posK;
556 final_projected_certain_writeK = final_alleged_writeK - bufsize_K;
557 for (curr = last; curr >= 0; curr--) {
558 cposK = g_tapecatalog->el[curr].tape_posK;
559 if (cposK < final_projected_certain_writeK) {
560 break;
561 }
562 }
563 if (curr < 0) {
564 log_it("Not far enough into tape to start deleting old archives from collection.");
565 mr_free(tmpdir);
566 return (0);
567 }
568
569 for (i = curr - 1; i >= 0 && curr - i < 10; i--) {
570 mr_asprintf(old_fname, "%s/%s", tmpdir, g_tapecatalog->el[i].fname);
571 unlink(old_fname);
572 mr_free(old_fname);
573 }
574 mr_free(tmpdir);
575 return (0);
576}
577
578
579
580
581/**
582 * Open the CD stream for input.
583 * @param bkpinfo The backup information structure. Passed to openin_tape().
584 * @return 0 for success, nonzero for failure.
585 * @note Equivalent to openin_tape() for now, but don't count on this behavior.
586 */
587int openin_cdstream()
588{
589 return (openin_tape());
590}
591
592/**
593 * FIFO used to read/write to the tape device.
594 * @bug This seems obsolete now that we call an external @c buffer program. Please look onto this.
595 */
596char g_tape_fifo[MAX_STR_LEN];
597
598
599
600int set_tape_block_size_with_mt(long internal_tape_block_size)
601{
602 char *tmp = NULL;
603 int res;
604
605 if (bkpinfo->media_device == NULL) {
606 return(1);
607 }
608
609 if (strncmp(bkpinfo->media_device, "/dev/", 5)) {
610 log_msg(1, "Not using 'mt setblk'. This isn't an actual /dev entry.");
611 return (0);
612 }
613 mr_asprintf(tmp, "mt -f %s setblk %ld", bkpinfo->media_device, internal_tape_block_size);
614 res = run_program_and_log_output(tmp, 3);
615 mr_free(tmp);
616 return (res);
617}
618
619/**
620 * Return the non-rewinding device when passed the normal one
621 * @param tapedev The tape device to open for writing.
622 * @note the caller needs to free the string returned
623 */
624char *get_non_rewind_dev(char *tapedev)
625{
626
627 char *ntapedev = NULL;
628 char *p = NULL;
629 char *q = NULL;
630 char *r = NULL;
631
632 ntapedev = (char *)malloc(strlen(tapedev)+sizeof(char));
633 p = strrchr(tapedev,'/');
634 if (p == NULL) {
635 log_it("Didn't find a '/' in %s",tapedev);
636 return(NULL);
637 }
638
639 /* Copy tapedev content up to the last / */
640 q = tapedev;
641 r = ntapedev;
642 while (q != p) {
643 *r = *q;
644 r++;
645 q++;
646 }
647 /* Copy the '/' */
648 *r = *q;
649 r++;
650 q++;
651 /* Adds a 'n' - non-rewinding */
652 *r = 'n';
653 r++;
654 /* Copy the rest of tapedev */
655 while (*q != '\0') {
656 *r = *q;
657 r++;
658 q++;
659 }
660 *r = '\0';
661 if (mt_says_tape_exists(ntapedev)) {
662 log_it("Non-rewinding tape device is %s",ntapedev);
663 } else {
664 log_it("Unable to find non-rewinding tape device.");
665 ntapedev = NULL;
666 }
667 return(ntapedev);
668}
669
670
671
672/**
673 * Handle OBDR if we were asked to do so
674 * @param tapedev The tape device to open for reading.
675 */
676int skip_obdr(void)
677{
678 char *command = NULL;
679 int res = 0;
680
681 if (bkpinfo->media_device == NULL) {
682 return(1);
683 }
684
685 log_it("Skipping OBDR headers");
686 mr_asprintf(command, "mt -f %s rewind",bkpinfo->media_device);
687 res = run_program_and_log_output(command, 1);
688 paranoid_free(command);
689
690 mr_asprintf(command, "mt -f %s fsf 2",bkpinfo->media_device);
691 res = run_program_and_log_output(command, 1);
692 paranoid_free(command);
693
694 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
695 return(res);
696}
697
698/**
699 * Handle OBDR if we were asked to do so
700 * @param tapedev The tape device to open for writing.
701 * @return 0 for success, nonzero for failure.
702 * @note This should be called ONLY from backup processes. It will OVERWRITE ANY
703 * EXISTING DATA on the tape!
704 */
705int create_obdr(void)
706{
707
708 char *command = NULL;
709 int res = 0;
710
711 if (bkpinfo->media_device == NULL) {
712 return(1);
713 }
714
715 log_it("Creating OBDR headers");
716 /* OBDR: First block 10 kB of zero bs = 512 */
717 mr_asprintf(command, "mt -f %s compression off",bkpinfo->media_device);
718 res = run_program_and_log_output(command, 1);
719 paranoid_free(command);
720
721 mr_asprintf(command, "mt -f %s rewind",bkpinfo->media_device);
722 res += run_program_and_log_output(command, 1);
723 paranoid_free(command);
724
725 set_tape_block_size_with_mt(512);
726
727 mr_asprintf(command, "dd if=/dev/zero of=%s bs=512 count=20",bkpinfo->media_device);
728 res += run_program_and_log_output(command, 1);
729 paranoid_free(command);
730
731 /* OBDR: then ISO boot image bs = 2048 */
732 set_tape_block_size_with_mt(2048);
733
734 mr_asprintf(command, "dd if=%s of=%s bs=2048",MINDI_CACHE"/mondorescue.iso",bkpinfo->media_device);
735 res += run_program_and_log_output(command, 1);
736 paranoid_free(command);
737
738 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
739
740 /* restore compression mode on */
741 mr_asprintf(command, "mt -f %s compression on",bkpinfo->media_device);
742 res = run_program_and_log_output(command, 1);
743 paranoid_free(command);
744
745 return(res);
746}
747
748
749/**
750 * Open the tape device for input.
751 * @param bkpinfo The backup information structure. Fields used:
752 * - @c bkpinfo->media_device
753 * - @c bkpinfo->tmpdir
754 * @return 0 for success, nonzero for failure.
755 * @note This will also work with a cdstream for now, but don't count on this behavior.
756 */
757int openin_tape()
758{
759 /*@ buffer ***************************************************** */
760 char fname[MAX_STR_LEN];
761 char *datablock;
762 char *tmp = NULL;
763 char old_cwd[MAX_STR_LEN];
764 char *outfname = NULL;
765 /*@ int ******************************************************* */
766 int i;
767 int j;
768 int res = 0;
769 long length, templong;
770 size_t k;
771 int retval = 0;
772 int ctrl_chr;
773
774 /*@ long long ************************************************* */
775 long long size;
776
777 /*@ pointers ************************************************** */
778 FILE *fout;
779
780 /*@ end vars *************************************************** */
781
782 g_tapecatalog = mr_malloc(sizeof(struct s_tapecatalog));
783 g_tapecatalog->entries = 0;
784 g_tape_posK = 0;
785 if (g_tape_stream) {
786 log_it("FYI - I won't 'openin' the tape. It's already open.");
787 return (0);
788 }
789
790 // mondoarchive should have configured everything to give the right non-rew device
791 if ((bkpinfo->use_obdr) && (bkpinfo->media_device != NULL)) {
792 res = skip_obdr();
793 if (res != 0) {
794 log_it("Not able to skip OBDR - Restore will have to be done manually");
795 }
796 } else {
797 if (bkpinfo->media_device == NULL) {
798 log_it("Not able to skip OBDR - Restore will have to be done manually");
799 return (1);
800 }
801 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
802 }
803
804 insist_on_this_tape_number(1);
805 mr_asprintf(outfname, "%s/tmp/all.tar.gz", bkpinfo->tmpdir);
806 make_hole_for_file(outfname);
807
808 log_it("Opening IN tape");
809 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'r', bkpinfo->internal_tape_block_size))) {
810 log_OS_error(g_tape_fifo);
811 log_to_screen("Cannot openin stream device");
812 mr_free(outfname);
813 return (1);
814 }
815 log_to_screen("Reading stream");
816 log_it("stream device = '%s'", bkpinfo->media_device);
817 /* skip data disks */
818 open_evalcall_form("Skipping data disks on stream");
819 log_to_screen("Skipping data disks on stream");
820 if (!(fout = fopen(outfname, "w"))) {
821 log_OS_error(outfname);
822 log_to_screen("Cannot openout datadisk all.tar.gz file");
823 mr_free(outfname);
824 return (-1);
825 }
826 if (!(datablock = (char *) malloc(256 * 1024))) {
827 log_to_screen("Unable to malloc 256*1024");
828 mr_free(outfname);
829 finish(1);
830 }
831 for (i = 0; i < 32; i++) {
832 for (j = 0; j < 4; j++) {
833 for (length = 0, k = 0; length < 256 * 1024; length += k) {
834 k = fread(datablock + length, 1, 256 * 1024 - length,
835 g_tape_stream);
836 }
837 if (fwrite(datablock, 1, (size_t) length, fout)) {
838 // FIXME
839 }
840 g_tape_posK += length / 1024;
841 }
842 if (i > 8) // otherwise, 'buffer' distorts calculations
843 {
844 templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
845 update_evalcall_form((int) (templong));
846 }
847 }
848 paranoid_fclose(fout);
849 paranoid_free(datablock);
850
851/* find initial blocks */
852 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
853 retval += res;
854 if (ctrl_chr != BLK_START_OF_TAPE) {
855 wrong_marker(BLK_START_OF_TAPE, ctrl_chr);
856 }
857 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
858 retval += res;
859 if (ctrl_chr != BLK_START_OF_BACKUP) {
860 wrong_marker(BLK_START_OF_BACKUP, ctrl_chr);
861 }
862 close_evalcall_form();
863 log_it("Saved all.tar.gz to '%s'", outfname);
864 if (getcwd(old_cwd, MAX_STR_LEN)) {
865 // FIXME
866 }
867 if (chdir(bkpinfo->tmpdir)) {
868 // FIXME
869 }
870 mr_asprintf(tmp, "tar -zxf %s ."MINDI_CACHE"/mondorestore.cfg 2> /dev/null", outfname);
871 paranoid_system(tmp);
872 mr_free(tmp);
873
874 paranoid_system("cp -f ."MINDI_CACHE"/mondorestore.cfg . 2> /dev/null");
875 if (chdir(old_cwd)) {
876 // FIXME
877 }
878 unlink(outfname);
879 mr_free(outfname);
880 return (retval);
881}
882
883
884/**
885 * Start writing to a CD stream.
886 * @param cddev The CD device to openout via cdrecord.
887 * @param speed The speed to write at.
888 * @return 0 for success, nonzero for failure.
889 * @note This should be called only from backup processes.
890 */
891int openout_cdstream(char *cddev, int speed)
892{
893 /*@ buffers ***************************************************** */
894 char *command = NULL;
895
896 /*@ end vars *************************************************** */
897
898 if (cddev == NULL) {
899 log_to_screen("Failed to openout NULL cddev");
900 return (1);
901 }
902 /* add 'dummy' if testing */
903 mr_asprintf(command, "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s", cddev, speed, MONDO_LOGFILE, MONDO_LOGFILE);
904 /* initialise the catalog */
905 g_current_media_number = 1;
906 if (!(g_tapecatalog = malloc(sizeof(struct s_tapecatalog)))) {
907 fatal_error("Cannot alloc mem for tape catalog");
908 }
909 g_tapecatalog->entries = 0;
910 /* log stuff */
911 log_it("Opening OUT cdstream with the command");
912 log_it(command);
913 /* log_it("Let's see what happens, shall we?"); */
914 g_tape_stream = popen(command, "w");
915 mr_free(command);
916
917 if (g_tape_stream) {
918 return (0);
919 } else {
920 log_to_screen("Failed to openout to cdstream (fifo)");
921 return (1);
922 }
923}
924
925
926/**
927 * Start writing to a tape device for the backup.
928 * Handle OBDR if we were asked to do so
929 * @param tapedev The tape device to open for writing.
930 * @return 0 for success, nonzero for failure.
931 * @note This should be called ONLY from backup processes. It will OVERWRITE ANY
932 * EXISTING DATA on the tape!
933 */
934int openout_tape() {
935
936g_current_media_number = 1;
937if (g_tape_stream) {
938 log_it("FYI - I won't 'openout' the tape. It's already open.");
939 return (0);
940}
941if (bkpinfo->media_device == NULL) {
942 log_it("Unable to openout NULL device");
943 return(1);
944}
945g_tapecatalog = mr_malloc(sizeof(struct s_tapecatalog));
946g_tapecatalog->entries = 0;
947g_tape_posK = 0;
948
949if (bkpinfo->use_obdr) {
950 create_obdr();
951} else {
952 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
953}
954log_it("Opening OUT tape");
955if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'w', bkpinfo->internal_tape_block_size))) {
956 log_OS_error(g_tape_fifo);
957 log_to_screen("Cannot openin stream device");
958 return (1);
959}
960return (0);
961}
962
963
964
965
966/**
967 * Copy a file from the opened stream (CD or tape) to @p outfile.
968 * @param outfile The file to write to.
969 * @param size The size of the file in the input stream.
970 * @return 0 for success, nonzero for failure.
971 */
972int
973read_file_from_stream_to_file(char *outfile, long long size)
974{
975
976 /*@ int ******************************************************** */
977 int res;
978
979 /*@ end vars *************************************************** */
980
981 res = read_file_from_stream_FULL(outfile, NULL, size);
982
983 return (res);
984}
985
986
987
988/**
989 * Copy a file from the currently opened stream (CD or tape) to the stream indicated
990 * by @p fout.
991 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
992 * @param fout The stream to write the file to.
993 * @param size The size of the file in bytes.
994 * @return 0 for success, nonzero for failure.
995 */
996int
997read_file_from_stream_to_stream(FILE * fout, long long size)
998{
999
1000 /*@ int ******************************************************** */
1001 int res;
1002
1003 /*@ end vars *************************************************** */
1004
1005 res = read_file_from_stream_FULL(NULL, fout, size);
1006/* fflush(g_tape_stream);
1007 fflush(fout);*/
1008 return (res);
1009}
1010
1011
1012
1013/**
1014 * Copy a file from the currently opened stream (CD or tape) to either a
1015 * @c FILE pointer indicating a currently-opened file, or a filename indicating
1016 * a new file to create. This is the backbone function that read_file_from_stream_to_file()
1017 * and read_file_from_stream_to_stream() are wrappers for.
1018 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
1019 * @param outfname If non-NULL, write to this file.
1020 * @param foutstream If non-NULL, write to this stream.
1021 * @param orig_size The original length of the file in bytes.
1022 * @return 0 for success, nonzero for failure.
1023 * @note Only @b one of @p outfname or @p foutstream may be non-NULL.
1024 */
1025int
1026read_file_from_stream_FULL(char *outfname, FILE * foutstream, long long orig_size)
1027{
1028 /*@ buffers ***************************************************** */
1029 char *datablock;
1030 char *temp_fname;
1031 char *temp_cksum;
1032 char *actual_cksum = NULL;
1033
1034 /*@ int ********************************************************* */
1035 int retval = 0;
1036#ifdef EXTRA_TAPE_CHECKSUMS
1037 int i, ch;
1038#endif
1039 int noof_blocks;
1040 int ctrl_chr;
1041 int res;
1042 /*@ pointers **************************************************** */
1043 FILE *fout;
1044
1045 /*@ long ***************************************************** */
1046 long bytes_to_write = 0L /*,i */ ;
1047// long bytes_successfully_read_in_this_time = 0;
1048
1049 /*@ long long *************************************************** */
1050 long long temp_size, size;
1051 long bytes_read, bytes_to_read;
1052 long long total_read_from_tape_for_this_file = 0;
1053 long long where_I_was_before_tape_change = 0;
1054 /*@ unsigned int ************************************************ */
1055 /* unsigned int ch; */
1056 unsigned int crc16;
1057 unsigned int crctt;
1058
1059 /*@ init ******************************************************* */
1060 malloc_string(temp_fname);
1061 malloc_string(temp_cksum);
1062 datablock = malloc(TAPE_BLOCK_SIZE);
1063 crc16 = 0;
1064 crctt = 0;
1065 size = orig_size;
1066
1067 /*@ end vars *************************************************** */
1068
1069 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1070 if (res) {
1071 // FIXME
1072 }
1073 if (orig_size != temp_size && orig_size != -1) {
1074 log_to_screen("output file's size should be %ld K but is apparently %ld K", (long) size >> 10, (long) temp_size >> 10);
1075 }
1076 if (ctrl_chr != BLK_START_FILE) {
1077 wrong_marker(BLK_START_FILE, ctrl_chr);
1078 return (1);
1079 }
1080
1081 if (foutstream) {
1082 fout = foutstream;
1083 } else {
1084 fout = fopen(outfname, "w");
1085 }
1086 if (!fout) {
1087 log_OS_error(outfname);
1088 log_to_screen("Cannot openout file");
1089 return (1);
1090 }
1091 total_read_from_tape_for_this_file = 0;
1092 for (noof_blocks = 0; size > 0;
1093 noof_blocks++, size -=
1094 bytes_to_write, total_read_from_tape_for_this_file +=
1095 bytes_read) {
1096 bytes_to_write =
1097 (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
1098 bytes_to_read = TAPE_BLOCK_SIZE;
1099 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
1100 while (bytes_read < bytes_to_read) { // next tape!
1101// crctt=crc16=0;
1102 where_I_was_before_tape_change = size;
1103 log_msg(4, "where_I_was_... = %lld",
1104 where_I_was_before_tape_change);
1105 start_to_read_from_next_tape();
1106 log_msg(4, "Started reading from next tape.");
1107 skip_incoming_files_until_we_find_this_one(temp_fname);
1108 log_msg(4, "Skipped irrelevant files OK.");
1109 for (size = orig_size; size > where_I_was_before_tape_change;
1110 size -= bytes_to_write) {
1111 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
1112 }
1113 log_msg(4, "'size' is now %lld (should be %lld)", size,
1114 where_I_was_before_tape_change);
1115 log_to_screen("Successfully re-sync'd tape");
1116 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
1117 }
1118
1119 if (fwrite(datablock, 1, (size_t) bytes_to_write, fout)) { // for blocking reasons, bytes_successfully_read_in isn't necessarily the same as bytes_to_write
1120 // FIXME
1121 }
1122
1123#ifdef EXTRA_TAPE_CHECKSUMS
1124 for (i = 0; i < (int) bytes_to_write; i++) {
1125 ch = datablock[i];
1126 crc16 = updcrcr(crc16, (unsigned) ch);
1127 crctt = updcrc(crctt, (unsigned) ch);
1128 }
1129#endif
1130 }
1131 log_msg(6, "Total read from tape for this file = %lld",
1132 total_read_from_tape_for_this_file);
1133 log_msg(6, ".......................... Should be %lld", orig_size);
1134 g_tape_posK += total_read_from_tape_for_this_file / 1024;
1135 mr_asprintf(actual_cksum, "%04x%04x", crc16, crctt);
1136 if (foutstream) { /*log_it("Finished writing to foutstream"); */
1137 } else {
1138 paranoid_fclose(fout);
1139 }
1140 res = read_header_block_from_stream(&temp_size, temp_cksum, &ctrl_chr);
1141 if (ctrl_chr != BLK_STOP_FILE) {
1142 wrong_marker(BLK_STOP_FILE, ctrl_chr);
1143 }
1144 if (strcmp(temp_cksum, actual_cksum)) {
1145 log_to_screen("actual cksum=%s; recorded cksum=%s", actual_cksum, temp_cksum);
1146 log_to_screen("%s (%ld K) is corrupt on tape", temp_fname, (long) orig_size >> 10);
1147 retval++;
1148 }
1149 mr_free(actual_cksum);
1150
1151 paranoid_free(datablock);
1152 paranoid_free(temp_fname);
1153 paranoid_free(temp_cksum);
1154 return (retval);
1155}
1156
1157
1158
1159/**
1160 * Read a header block from the currently opened stream (CD or tape).
1161 * This block indicates the length of the following file (if it's file-related)
1162 * the filename (if it's file-related), and the block type.
1163 * @param plen Where to put the length of the file. Valid only for file-related header blocks.
1164 * @param filename Where to put the name of the file. Valid only for file-related header blocks.
1165 * @param pcontrol_char Where to put the type of block (e.g. start-file, end-file, start-tape, ...)
1166 * @return 0 for success, nonzero for failure.
1167 * @note If you read a marker (@p pcontrol_char) you're not expecting, you can call wrong_marker().
1168 */
1169int
1170read_header_block_from_stream(long long *plen, char *filename,
1171 int *pcontrol_char)
1172{
1173
1174 /*@ buffers ***************************************************** */
1175 char *tempblock;
1176
1177 /*@ int ********************************************************* */
1178 int i, retval;
1179
1180 /*@ end vars *************************************************** */
1181
1182 tempblock = (char *) malloc((size_t) TAPE_BLOCK_SIZE);
1183
1184 for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
1185 tempblock[i] = 0;
1186 }
1187 while (!(*pcontrol_char = tempblock[7000])) {
1188 g_tape_posK += fread(tempblock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream) / 1024;
1189 }
1190 memcpy((char *) plen, tempblock + 7001, sizeof(long long));
1191 if (strcmp(tempblock + 6000 + *pcontrol_char, STR_HEADER)) {
1192 log_it("Bad header block at %ld K", (long) g_tape_posK);
1193 }
1194 strcpy(filename, tempblock + 1000);
1195 if (*pcontrol_char == BLK_ABORTED_BACKUP) {
1196 log_to_screen("I can't verify an aborted backup.");
1197 retval = 1;
1198 } else {
1199 retval = 0;
1200 }
1201 for (i = 1000; i < 1020; i++) {
1202 if (tempblock[i] < 32 || tempblock[i] > 126) {
1203 tempblock[i] = ' ';
1204 }
1205 }
1206 tempblock[i] = '\0';
1207 log_msg(6, "%s (fname=%s, size=%ld K)",
1208 marker_to_string(*pcontrol_char), tempblock + 1000,
1209 (long) (*plen) >> 10);
1210 paranoid_free(tempblock);
1211 return (retval);
1212}
1213
1214
1215
1216/**
1217 * Add specified file/slice to the internal catalog of all archives written.
1218 * This lets us restart on a new CD/tape/whatever if it runs out of room. We just
1219 * write the last [buffer size] MB from the catalog to the new tape, so we know
1220 * we have @e all archives on some CD/tape/whatever.
1221 * @param type The type of file we're cataloging (afioball, slice, something else)
1222 * @param number The fileset number or biggiefile number.
1223 * @param aux The slice number if it's a biggiefile, or any other additional info.
1224 * @param fn The original full pathname of the file we're recording.
1225 * @return The index of the record we just added.
1226 */
1227int register_in_tape_catalog(t_archtype type, int number, long aux,
1228 char *fn)
1229{
1230 int last;
1231 char fname[MAX_TAPECAT_FNAME_LEN+1];
1232 char *p;
1233
1234 p = strrchr(fn, '/');
1235 if (p) {
1236 p++;
1237 } else {
1238 p = fn;
1239 }
1240 strncpy(fname, p, MAX_TAPECAT_FNAME_LEN);
1241 fname[MAX_TAPECAT_FNAME_LEN] = '\0';
1242 last = g_tapecatalog->entries;
1243 if (last >= MAX_TAPECATALOG_ENTRIES) {
1244 log_it
1245 ("Warning - can't log #%d in tape catalog - too many entries already",
1246 number);
1247 return (-1);
1248 }
1249 g_tapecatalog->el[last].type = type;
1250 g_tapecatalog->el[last].number = number;
1251 g_tapecatalog->el[last].aux = aux;
1252 g_tapecatalog->el[last].tape_posK = g_tape_posK;
1253 strcpy(g_tapecatalog->el[last].fname, fname);
1254 g_tapecatalog->entries++;
1255 return (last); // returns the index of the record we've jsut added
1256}
1257
1258
1259
1260
1261/**
1262 * Decide whether we should start a new tape. This is TRUE if we've run out of tape
1263 * (got SIGPIPE) or look like we will.
1264 * @param mediasize The size of the tape in megabytes.
1265 * @param length_of_incoming_file The length of the file we're about to write, in bytes.
1266 * @bug This seems like it'll only work for media_size != autodetect, but Mondo only allows
1267 * autodetecting the size. Huh?
1268 */
1269
1270/* BERLIOS: Should be reviewed for mediasize being a off_t ??? */
1271bool
1272should_we_write_to_next_tape(long mediasize,
1273 off_t length_of_incoming_file)
1274{
1275 /*@ bool's ***************************************************** */
1276 bool we_need_a_new_tape = FALSE;
1277
1278 /*@ end vars *************************************************** */
1279
1280 if (mediasize == 0) {
1281 return (FALSE);
1282 }
1283 if (mediasize > 0 && (g_tape_posK >> 10 >= mediasize)) {
1284 log_it("mediasize = %ld", mediasize);
1285 we_need_a_new_tape = TRUE;
1286 log_to_screen("Should have started a new tape/CD already");
1287 }
1288 if ((g_tape_posK + length_of_incoming_file / 1024) >> 10 >=
1289 mediasize - (SLICE_SIZE * 4 / 1024)) {
1290 log_it("g_tape_posK = %ld\nmediasize = %ld\n", g_tape_posK,
1291 mediasize);
1292 we_need_a_new_tape = TRUE;
1293 }
1294 return (we_need_a_new_tape);
1295}
1296
1297
1298/**
1299 * Seek through the stream until we find a header block where the NAME field matches
1300 * @p the_file_I_was_reading. This is useful if you've just started reading from
1301 * a new tape and want to find the file you were reading when the tape ended.
1302 * @param the_file_I_was_reading File name to look for.
1303 * @return 0 for success, nonzero for failure.
1304 */
1305int skip_incoming_files_until_we_find_this_one(char
1306 *the_file_I_was_reading)
1307{
1308 char *pA;
1309 char *pB;
1310 int res;
1311 int ctrl_chr;
1312 char *temp_fname;
1313 char *datablock;
1314 long long temp_size, size;
1315 long bytes_to_write;
1316
1317 datablock = malloc(TAPE_BLOCK_SIZE);
1318 malloc_string(temp_fname);
1319 pB = strrchr(the_file_I_was_reading, '/');
1320 if (pB) {
1321 pB++;
1322 } else {
1323 pB = the_file_I_was_reading;
1324 }
1325 log_msg(1, "skip_incoming_..(%s)", pB);
1326 log_msg(2, "Looking for initial START_AN_AFIO_OR_SLICE");
1327 ctrl_chr = -1;
1328 while (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1329 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1330 if (res) {
1331 // FIXME
1332 }
1333 if (ctrl_chr == BLK_START_AN_AFIO_OR_SLICE) {
1334 break;
1335 }
1336 log_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1337 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1338 log_msg(3, "Still trying to re-sync w/ tape");
1339 }
1340 while (ctrl_chr != BLK_START_FILE) {
1341 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1342 if (res) {
1343 //FIXME
1344 }
1345 if (ctrl_chr == BLK_START_FILE) {
1346 break;
1347 }
1348 log_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1349 wrong_marker(BLK_START_FILE, ctrl_chr);
1350 log_msg(3, "Still trying to re-sync w/ tape");
1351 }
1352 pA = strrchr(temp_fname, '/');
1353 if (pA) {
1354 pA++;
1355 } else {
1356 pA = temp_fname;
1357 }
1358 pB = strrchr(the_file_I_was_reading, '/');
1359 if (pB) {
1360 pB++;
1361 } else {
1362 pB = the_file_I_was_reading;
1363 }
1364 while (strcmp(pA, pB)) {
1365 log_msg(6, "Skipping %s (it's not %s)", temp_fname, the_file_I_was_reading);
1366 for (size = temp_size; size > 0; size -= bytes_to_write) {
1367 bytes_to_write =
1368 (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
1369 if (fread(datablock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream)) {
1370 // FIXME - needs error-checking and -catching
1371 }
1372 }
1373 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1374 if (ctrl_chr != BLK_STOP_FILE) {
1375 wrong_marker(BLK_STOP_FILE, ctrl_chr);
1376 }
1377 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1378 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
1379 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
1380 }
1381 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1382 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1383 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1384 }
1385 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1386 if (ctrl_chr != BLK_START_FILE) {
1387 wrong_marker(BLK_START_FILE, ctrl_chr);
1388 }
1389 pA = strrchr(temp_fname, '/');
1390 if (pA) {
1391 pA++;
1392 } else {
1393 pA = temp_fname;
1394 }
1395 pB = strrchr(the_file_I_was_reading, '/');
1396 if (pB) {
1397 pB++;
1398 } else {
1399 pB = the_file_I_was_reading;
1400 }
1401 }
1402 log_msg(2, "Reading %s (it matches %s)", temp_fname, the_file_I_was_reading);
1403 paranoid_free(temp_fname);
1404 paranoid_free(datablock);
1405 return (0);
1406}
1407
1408
1409/**
1410 * Start to read from the next tape. Assumes the user has already inserted it.
1411 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1412 * @return 0 for success, nonzero for failure.
1413 */
1414int start_to_read_from_next_tape()
1415{
1416 /*@ int ********************************************************* */
1417 int res = 0;
1418 char *sz_msg;
1419 int ctrlchr;
1420 long long temp_size;
1421 malloc_string(sz_msg);
1422 /*@ end vars *************************************************** */
1423
1424 if (bkpinfo->media_device == NULL) {
1425 log_it("Unable to open in from NULL device");
1426 return (1);
1427 }
1428
1429 paranoid_pclose(g_tape_stream);
1430 sync();
1431 sync();
1432 sync();
1433 log_it("Next tape requested.");
1434 insist_on_this_tape_number(g_current_media_number + 1); // will increment it, too
1435 log_it("Opening IN the next tape");
1436 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'r', bkpinfo->internal_tape_block_size))) {
1437 log_OS_error(g_tape_fifo);
1438 log_to_screen("Cannot openin stream device");
1439 return (1);
1440 }
1441 g_tape_posK = 0;
1442 g_sigpipe = FALSE;
1443 res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1444 if (ctrlchr != BLK_START_OF_TAPE) {
1445 wrong_marker(BLK_START_OF_TAPE, ctrlchr);
1446 }
1447 res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1448 if (ctrlchr != BLK_START_OF_BACKUP) {
1449 wrong_marker(BLK_START_OF_BACKUP, ctrlchr);
1450 } else {
1451 log_msg(3, "Next tape opened OK. Whoopee!");
1452 }
1453 paranoid_free(sz_msg);
1454 return (res);
1455}
1456
1457
1458
1459/**
1460 * Start to write to the next tape. Assume the user has already inserted it.
1461 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1462 * @return 0 for success, nonzero for failure.
1463 */
1464int start_to_write_to_next_tape()
1465{
1466 int res = 0;
1467 char *command = NULL;
1468
1469 if (bkpinfo->media_device == NULL) {
1470 log_it("Unable to open out from NULL device");
1471 return (1);
1472 }
1473
1474 paranoid_pclose(g_tape_stream);
1475 sync();
1476 sync();
1477 sync();
1478 log_it("New tape requested.");
1479 insist_on_this_tape_number(g_current_media_number + 1); // will increment g_current_media, too
1480 if (bkpinfo->backup_media_type == cdstream) {
1481 mr_asprintf(command, "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s", bkpinfo->media_device, bkpinfo->cdrw_speed, MONDO_LOGFILE, MONDO_LOGFILE);
1482 log_it("Opening OUT to next CD with the command");
1483 log_it(command);
1484 log_it("Let's see what happens, shall we?");
1485 g_tape_stream = popen(command, "w");
1486 mr_free(command);
1487
1488 if (!g_tape_stream) {
1489 log_to_screen("Failed to openout to cdstream (fifo)");
1490 return (1);
1491 }
1492 } else {
1493 log_it("Opening OUT to next tape");
1494 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'w', bkpinfo->internal_tape_block_size))) {
1495 log_OS_error(g_tape_fifo);
1496 log_to_screen("Cannot openin stream device");
1497 return (1);
1498 }
1499 }
1500 g_tape_posK = 0;
1501 g_sigpipe = FALSE;
1502 res += write_header_block_to_stream((off_t)0, "start-of-tape", BLK_START_OF_TAPE); /* just in case */
1503 res += write_header_block_to_stream((off_t)0, "start-of-backup", BLK_START_OF_BACKUP); /* just in case */
1504 return (res);
1505}
1506
1507
1508
1509
1510/**
1511 * Write a bufferfull of the most recent archives to the tape. The
1512 * rationale behind this is a bit complex. If the previous tape ended
1513 * suddenly (EOF or otherwise) some archives were probably left in the
1514 * buffer. That means that Mondo thinks they have been written, but
1515 * the external binary @c buffer has not actually written them. So to
1516 * be safe, we start the new tape by writing the last bufferfull from
1517 * the old one. This insures that all archives will be on at least
1518 * one tape. Sounds inelegant, but it works.
1519 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir is the only field used.
1520 * @return 0 for success, nonzero for failure.
1521 */
1522int write_backcatalog_to_tape()
1523{
1524 int i, last, res = 0;
1525 char *fname = NULL;
1526
1527 log_msg(2, "I am now writing back catalog to tape");
1528 last = g_tapecatalog->entries - 1;
1529 for (i = 0; i <= last; i++) {
1530 mr_asprintf(fname, "%s/tmpfs/backcatalog/%s", bkpinfo->tmpdir, g_tapecatalog->el[i].fname);
1531 if (!does_file_exist(fname)) {
1532 log_msg(6, "Can't write %s - it doesn't exist.", fname);
1533 } else {
1534 write_header_block_to_stream(length_of_file(fname),
1535 "start-backcatalog-afio-or-slice",
1536 BLK_START_AN_AFIO_OR_SLICE);
1537 log_msg(2, "Writing %s", fname);
1538 if (write_file_to_stream_from_file(fname)) {
1539 res++;
1540 log_msg(2, "%s failed", fname);
1541 }
1542 if (i != last) {
1543 write_header_block_to_stream((off_t)0,
1544 "stop-backcatalog-afio-or-slice",
1545 BLK_STOP_AN_AFIO_OR_SLICE);
1546 }
1547 }
1548 mr_free(fname);
1549 }
1550 log_msg(2, "Finished writing back catalog to tape");
1551 return (res);
1552}
1553
1554
1555
1556/**
1557 * Write all.tar.gz (produced by Mindi) to the first 32M of the first tape.
1558 * @param fname The path to all.tar.gz.
1559 * @return 0 for success, nonzero for failure.
1560 */
1561int write_data_disks_to_stream(char *fname)
1562{
1563 /*@ pointers *************************************************** */
1564 FILE *fin;
1565
1566 /*@ long ******************************************************* */
1567 long m = -1;
1568 long templong;
1569
1570 /*@ int ******************************************************** */
1571 int i, j;
1572
1573 /*@ buffers **************************************************** */
1574 char tempblock[256 * 1024];
1575
1576 /*@ end vars *************************************************** */
1577
1578 open_evalcall_form("Writing data disks to tape");
1579 log_to_screen("Writing data disks to tape");
1580 log_it("Data disks = %s", fname);
1581 if (!does_file_exist(fname)) {
1582 log_to_screen("Cannot find %s", fname);
1583 return (1);
1584 }
1585 if (!(fin = fopen(fname, "r"))) {
1586 log_OS_error(fname);
1587 fatal_error("Cannot openin the data disk");
1588 }
1589 for (i = 0; i < 32; i++) { /* 32MB */
1590 for (j = 0; j < 4; j++) { /* 256K x 4 = 1MB (1024K) */
1591 if (!feof(fin)) {
1592 m = (long) fread(tempblock, 1, 256 * 1024, fin);
1593 } else {
1594 m = 0;
1595 }
1596 for (; m < 256 * 1024; m++) {
1597 tempblock[m] = '\0';
1598 }
1599 g_tape_posK +=
1600 fwrite(tempblock, 1, 256 * 1024, g_tape_stream) / 1024;
1601 }
1602 if (i > g_tape_buffer_size_MB) // otherwise, 'buffer' distorts calculations
1603 {
1604 templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
1605 update_evalcall_form((int) (templong));
1606 }
1607 }
1608 paranoid_fclose(fin);
1609 close_evalcall_form();
1610 return (0);
1611}
1612
1613
1614
1615
1616/**
1617 * Copy @p infile to the opened stream (CD or tape).
1618 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
1619 * @param infile The file to write to the stream.
1620 * @return 0 for success, nonzero for failure.
1621 */
1622int write_file_to_stream_from_file(char *infile)
1623{
1624 /*@ buffers **************************************************** */
1625 char datablock[TAPE_BLOCK_SIZE];
1626 char *checksum = NULL;
1627 char *infile_basename;
1628
1629 /*@ int ******************************************************** */
1630 int retval = 0;
1631 int noof_blocks;
1632
1633 /* unsigned int ch; */
1634 unsigned int crc16;
1635 unsigned int crctt;
1636
1637 /*@ pointers *************************************************** */
1638 FILE *fin;
1639 char *p;
1640
1641 /*@ long ******************************************************* */
1642 long bytes_to_read = 0;
1643 long i;
1644
1645 off_t filesize;
1646
1647#ifdef EXTRA_TAPE_CHECKSUMS
1648 int ch;
1649#endif
1650
1651 /*@ initialize ************************************************ */
1652 crc16 = 0;
1653 crctt = 0;
1654
1655
1656
1657 /*@ end vars *************************************************** */
1658
1659 infile_basename = strrchr(infile, '/');
1660 if (infile_basename) {
1661 infile_basename++;
1662 } else {
1663 infile_basename = infile;
1664 }
1665 filesize = length_of_file(infile);
1666 if (should_we_write_to_next_tape
1667 (bkpinfo->media_size, filesize)) {
1668 start_to_write_to_next_tape();
1669 write_backcatalog_to_tape();
1670 }
1671 p = strrchr(infile, '/');
1672 if (!p) {
1673 p = infile;
1674 } else {
1675 p++;
1676 }
1677 log_it("Writing file '%s' to tape (%ld KB)", p, (long) filesize >> 10);
1678 write_header_block_to_stream(filesize, infile_basename,
1679 BLK_START_FILE);
1680//go_here_to_restart_saving_of_file:
1681 if (!(fin = fopen(infile, "r"))) {
1682 log_OS_error(infile);
1683 return (1);
1684 }
1685 for (noof_blocks = 0; filesize > 0;
1686 noof_blocks++, filesize -= bytes_to_read) {
1687 if (filesize < TAPE_BLOCK_SIZE) {
1688 bytes_to_read = (long) filesize;
1689 for (i = 0; i < TAPE_BLOCK_SIZE; i++) {
1690 datablock[i] = '\0';
1691 }
1692 } else {
1693 bytes_to_read = TAPE_BLOCK_SIZE;
1694 }
1695 if (fread(datablock, 1, (size_t) bytes_to_read, fin)) {
1696 // FIXME
1697 }
1698 g_tape_posK +=
1699 fwrite(datablock, 1, /*bytes_to_read */
1700 (size_t) TAPE_BLOCK_SIZE,
1701 g_tape_stream) / 1024;
1702 if (g_sigpipe) {
1703 log_it("Sigpipe occurred recently. I'll start a new tape.");
1704 fclose(fin);
1705 g_sigpipe = FALSE;
1706 start_to_write_to_next_tape();
1707 write_backcatalog_to_tape(); // kinda-sorta recursive :)
1708 return (0);
1709 }
1710#ifdef EXTRA_TAPE_CHECKSUMS
1711 for (i = 0; i < bytes_to_read; i++) {
1712 ch = datablock[i];
1713 crc16 = updcrcr(crc16, (unsigned) ch);
1714 crctt = updcrc(crctt, (unsigned) ch);
1715 }
1716#endif
1717 }
1718 paranoid_fclose(fin);
1719 mr_asprintf(checksum, "%04x%04x", crc16, crctt);
1720 /* BERLIOS: what does it do ??? */
1721 write_header_block_to_stream((off_t)g_current_media_number, checksum, BLK_STOP_FILE);
1722 mr_free(checksum);
1723
1724// log_it("File '%s' written to tape.", infile);
1725 return (retval);
1726}
1727
1728
1729
1730
1731
1732/**
1733 * Write a header block to the opened stream (CD or tape).
1734 * @param length_of_incoming_file The length to store in the header block.
1735 * Usually matters only if this is a file-related header, in which case it should
1736 * be the length of the file that will follow.
1737 * @param filename The filename to store in the header block. Usually matters
1738 * only if this is a file-related header, in which case this should be the name
1739 * if the file that will follow.
1740 * @param control_char The type of header block this is (start-file, end-file, start-tape, ...)
1741 * @return 0 for success, nonzero for failure.
1742 */
1743int
1744write_header_block_to_stream(off_t length_of_incoming_file,
1745 char *filename, int control_char)
1746{
1747 /*@ buffers **************************************************** */
1748 char tempblock[TAPE_BLOCK_SIZE];
1749 char *p;
1750
1751 /*@ int ******************************************************** */
1752 int i;
1753
1754 off_t olen;
1755
1756 /*@ end vars *************************************************** */
1757
1758
1759 olen = length_of_incoming_file;
1760 p = strrchr(filename, '/'); /* Make 'em go, "Unnnh!" Oh wait, that was _Master_ P... */
1761 if (!p) {
1762 p = filename;
1763 } else {
1764 p++;
1765 }
1766 if (!g_tape_stream) {
1767 log_to_screen("You're not backing up to tape. Why write a tape header?");
1768 return (1);
1769 }
1770 for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
1771 tempblock[i] = 0;
1772 }
1773 sprintf(tempblock + 6000 + control_char, STR_HEADER);
1774 tempblock[7000] = control_char;
1775 memcpy(tempblock + 7001, (char *) &olen, sizeof(off_t));
1776 strcpy(tempblock + 1000, filename);
1777 g_tape_posK += fwrite(tempblock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream) / 1024;
1778 log_msg(6, "%s (fname=%s, size=%ld K)", marker_to_string(control_char), p, (long) length_of_incoming_file >> 10);
1779 return (0);
1780}
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791/**
1792 * Log (to screen) an erroneous marker, along with what it should have been.
1793 * @param should_be What we were expecting.
1794 * @param it_is What we got.
1795 */
1796void wrong_marker(int should_be, int it_is)
1797{
1798 log_to_screen("Wrong marker! (Should be %s, is actually %s)", marker_to_string(should_be), marker_to_string(it_is));
1799}
1800
1801/* @} - end of streamGroup */
Note: See TracBrowser for help on using the repository browser.