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

Last change on this file since 3872 was 3872, checked in by Bruno Cornec, 3 months ago

Rewrite find_dvd_device

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