source: MondoRescue/trunk/mondo/src/common/libmondo-stream.c@ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 18 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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