source: MondoRescue/branches/3.0/mondo/src/common/libmondo-stream.c@ 3192

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