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

Last change on this file since 1881 was 1881, checked in by bruno, 12 years ago

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

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