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

Last change on this file since 541 was 541, checked in by bcornec, 18 years ago

Stable is reverted to r436 (2.0.7) to put it in line with 2.0.8 and start from there over

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