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

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

Trunk: indent on all source files

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