source: MondoRescue/branches/3.3/mondo/src/common/libmondo-stream.c@ 3746

Last change on this file since 3746 was 3646, checked in by Bruno Cornec, 7 years ago

Do not exit too early when dealing with an empty file, as the verify step isn't working if we do. Just avoid to run what would create an issue instead (David C. Partridge david.partridge_at_perdrix.co.uk)

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