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

Last change on this file since 684 was 684, checked in by bcornec, 14 years ago

Attempt to fix Bug #7820 Does not backup a file greater than 2 GB
Report from taps23@…
Changed legnth_of_file to off_t for ftello support and all relative changes made as well in various functions to be consistent

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