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

Last change on this file since 1 was 1, checked in by bcornec, 19 years ago

Initial import from latest mondo-2.04_cvs_20050503/mindi-1.04_cvs_20050503 on http://www.mondorescue.org

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