source: MondoRescue/branches/stable/mondo/src/common/libmondo-stream.c@ 1123

Last change on this file since 1123 was 1123, checked in by Bruno Cornec, 17 years ago

Again linker fixes (hopefully last time for now)

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