source: MondoRescue/branches/2.2.5/mondo/src/common/libmondo-stream.c@ 1881

Last change on this file since 1881 was 1881, checked in by Bruno Cornec, 16 years ago

Should fix the problem with the prefix always asked at restore time, even when it's not NFS

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